From 328b62ae5067619e59da42f6db6703d3b327f1a2 Mon Sep 17 00:00:00 2001 From: ilija42 <57732589+ilija42@users.noreply.github.com> Date: Wed, 18 Sep 2024 23:36:16 +0200 Subject: [PATCH 01/20] [BCFR-203] Improve CR value comparator querying (topics and data words) by doing encoding in the relayer (#14207) * Add EVM CR topic and data words types to codec for QueryKey filtering * temp * Update Chain Reader Tester contract to match common testing structs * Fix codecEntry ToNative() method bad error message * Add support for filtering over indexed topics with query key * Remove the need for Chain Reader Config InputFields - Params are typed into all topics and checked for nil - Allows for searching same read with diff params - Allows to query filter and GetLatestValue same event * Implement Chain Reader data words types init and packing * cleanup changes * Implement querying by data words with value comparators as any * Fix CR topic querying and simplify value comparator encoding * Simplify CR event topic and data words typing * Refactor CR topic encoding a bit to be simpler * Fix lint, changeset and correct a minor test failure * [Bot] Update changeset file with jira issue * Add changeset * Update changesets * lint * Separate loop and non loop CR tests, bump go mod and minor fix * Fix rebase issues * Handle CR value comparator Querying codec type creation and lookup * Update changeset associated ticket numbers * lint * Add todos * Remove unused indexes from ChainReader DataWords config * Update common * Bump common --------- Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com> --- .changeset/lucky-zebras-reflect.md | 7 + contracts/.changeset/fluffy-papayas-chew.md | 8 + .../shared/test/helpers/ChainReaderTester.sol | 6 +- .../ccip/configs/evm/contract_reader.go | 5 - core/chains/evm/logpoller/orm_test.go | 40 +- core/chains/evm/logpoller/parser.go | 31 +- core/chains/evm/logpoller/parser_test.go | 16 +- .../chain_reader_tester.go | 22 +- ...rapper-dependency-versions-do-not-edit.txt | 2 +- core/scripts/go.mod | 10 +- core/scripts/go.sum | 20 +- .../relay/evm/chain_components_test.go | 6 +- core/services/relay/evm/chain_reader.go | 221 ++++--- ...n_reader_historical_client_wrapper_test.go | 7 +- core/services/relay/evm/chain_writer.go | 4 +- core/services/relay/evm/codec/codec.go | 8 + .../chain_components_interface_tester.go | 13 +- .../relay/evm/evmtesting/run_tests.go | 42 ++ core/services/relay/evm/read/batch.go | 13 +- core/services/relay/evm/read/bindings.go | 21 +- core/services/relay/evm/read/bindings_test.go | 6 +- core/services/relay/evm/read/event.go | 614 ++++++++++-------- core/services/relay/evm/read/method.go | 5 +- core/services/relay/evm/types/codec_entry.go | 10 +- core/services/relay/evm/types/types.go | 8 +- core/services/relay/evm/types/types_test.go | 5 +- go.mod | 10 +- go.sum | 20 +- integration-tests/go.mod | 10 +- integration-tests/go.sum | 20 +- integration-tests/load/go.mod | 10 +- integration-tests/load/go.sum | 20 +- 32 files changed, 701 insertions(+), 539 deletions(-) create mode 100644 .changeset/lucky-zebras-reflect.md create mode 100644 contracts/.changeset/fluffy-papayas-chew.md diff --git a/.changeset/lucky-zebras-reflect.md b/.changeset/lucky-zebras-reflect.md new file mode 100644 index 00000000000..2d4c875f643 --- /dev/null +++ b/.changeset/lucky-zebras-reflect.md @@ -0,0 +1,7 @@ +--- +"chainlink": minor +--- + +#internal Implement EVM ChainReader ValueComparator filtering by non-indexed event data. Right now only simple non indexed data where byte offsets don't exist is supported. + +BCFR-203 \ No newline at end of file diff --git a/contracts/.changeset/fluffy-papayas-chew.md b/contracts/.changeset/fluffy-papayas-chew.md new file mode 100644 index 00000000000..b76e41cfbe0 --- /dev/null +++ b/contracts/.changeset/fluffy-papayas-chew.md @@ -0,0 +1,8 @@ +--- +'@chainlink/contracts': minor +--- + +#internal Change Chain Reader testing contract Triggered event for easier testing of filtering by non indexed evm data. + + +BCFR-203 \ No newline at end of file diff --git a/contracts/src/v0.8/shared/test/helpers/ChainReaderTester.sol b/contracts/src/v0.8/shared/test/helpers/ChainReaderTester.sol index 709d00cc382..e3b277119ae 100644 --- a/contracts/src/v0.8/shared/test/helpers/ChainReaderTester.sol +++ b/contracts/src/v0.8/shared/test/helpers/ChainReaderTester.sol @@ -26,11 +26,11 @@ struct InnerTestStruct { contract ChainReaderTester { event Triggered( int32 indexed field, - string differentField, uint8 oracleId, uint8[32] oracleIds, address Account, address[] Accounts, + string differentField, int192 bigField, MidLevelTestStruct nestedStruct ); @@ -109,15 +109,15 @@ contract ChainReaderTester { function triggerEvent( int32 field, - string calldata differentField, uint8 oracleId, uint8[32] calldata oracleIds, address account, address[] calldata accounts, + string calldata differentField, int192 bigField, MidLevelTestStruct calldata nestedStruct ) public { - emit Triggered(field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct); + emit Triggered(field, oracleId, oracleIds, account, accounts, differentField, bigField, nestedStruct); } function triggerEventWithDynamicTopic(string calldata field) public { diff --git a/core/capabilities/ccip/configs/evm/contract_reader.go b/core/capabilities/ccip/configs/evm/contract_reader.go index 7b04b42e8d9..18aa07cc022 100644 --- a/core/capabilities/ccip/configs/evm/contract_reader.go +++ b/core/capabilities/ccip/configs/evm/contract_reader.go @@ -194,11 +194,6 @@ var SourceReaderConfig = evmrelaytypes.ChainReaderConfig{ consts.EventNameCCIPMessageSent: { ChainSpecificName: mustGetEventName("CCIPMessageSent", onrampABI), ReadType: evmrelaytypes.Event, - EventDefinitions: &evmrelaytypes.EventDefinitions{ - GenericDataWordNames: map[string]uint8{ - consts.EventAttributeSequenceNumber: 5, - }, - }, }, }, }, diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go index f5f44acf3df..1fb20a03af2 100644 --- a/core/chains/evm/logpoller/orm_test.go +++ b/core/chains/evm/logpoller/orm_test.go @@ -606,8 +606,8 @@ func TestORM_IndexedLogs(t *testing.T) { } for idx, value := range topicValues { - topicFilters.Expressions[idx] = logpoller.NewEventByTopicFilter(topicIdx, []primitives.ValueComparator{ - {Value: logpoller.EvmWord(value).Hex(), Operator: primitives.Eq}, + topicFilters.Expressions[idx] = logpoller.NewEventByTopicFilter(topicIdx, []logpoller.HashedValueComparator{ + {Value: logpoller.EvmWord(value), Operator: primitives.Eq}, }) } @@ -702,8 +702,8 @@ func TestORM_IndexedLogs(t *testing.T) { Expressions: []query.Expression{ logpoller.NewAddressFilter(addr), logpoller.NewEventSigFilter(eventSig), - logpoller.NewEventByTopicFilter(1, []primitives.ValueComparator{ - {Value: logpoller.EvmWord(2).Hex(), Operator: primitives.Gte}, + logpoller.NewEventByTopicFilter(1, []logpoller.HashedValueComparator{ + {Value: logpoller.EvmWord(2), Operator: primitives.Gte}, }), query.Confidence(primitives.Unconfirmed), }, @@ -717,11 +717,11 @@ func TestORM_IndexedLogs(t *testing.T) { return []query.Expression{ logpoller.NewAddressFilter(addr), logpoller.NewEventSigFilter(eventSig), - logpoller.NewEventByTopicFilter(topicIdx, []primitives.ValueComparator{ - {Value: logpoller.EvmWord(min).Hex(), Operator: primitives.Gte}, + logpoller.NewEventByTopicFilter(topicIdx, []logpoller.HashedValueComparator{ + {Value: logpoller.EvmWord(min), Operator: primitives.Gte}, }), - logpoller.NewEventByTopicFilter(topicIdx, []primitives.ValueComparator{ - {Value: logpoller.EvmWord(max).Hex(), Operator: primitives.Lte}, + logpoller.NewEventByTopicFilter(topicIdx, []logpoller.HashedValueComparator{ + {Value: logpoller.EvmWord(max), Operator: primitives.Lte}, }), query.Confidence(primitives.Unconfirmed), } @@ -876,11 +876,11 @@ func TestORM_DataWords(t *testing.T) { return []query.Expression{ logpoller.NewAddressFilter(addr), logpoller.NewEventSigFilter(eventSig), - logpoller.NewEventByWordFilter(eventSig, wordIdx, []primitives.ValueComparator{ - {Value: logpoller.EvmWord(word1).Hex(), Operator: primitives.Gte}, + logpoller.NewEventByWordFilter(wordIdx, []logpoller.HashedValueComparator{ + {Value: logpoller.EvmWord(word1), Operator: primitives.Gte}, }), - logpoller.NewEventByWordFilter(eventSig, wordIdx, []primitives.ValueComparator{ - {Value: logpoller.EvmWord(word2).Hex(), Operator: primitives.Lte}, + logpoller.NewEventByWordFilter(wordIdx, []logpoller.HashedValueComparator{ + {Value: logpoller.EvmWord(word2), Operator: primitives.Lte}, }), query.Confidence(primitives.Unconfirmed), } @@ -944,8 +944,8 @@ func TestORM_DataWords(t *testing.T) { filter := []query.Expression{ logpoller.NewAddressFilter(addr), logpoller.NewEventSigFilter(eventSig), - logpoller.NewEventByWordFilter(eventSig, 0, []primitives.ValueComparator{ - {Value: logpoller.EvmWord(1).Hex(), Operator: primitives.Gte}, + logpoller.NewEventByWordFilter(0, []logpoller.HashedValueComparator{ + {Value: logpoller.EvmWord(1), Operator: primitives.Gte}, }), query.Confidence(primitives.Unconfirmed), } @@ -1667,8 +1667,8 @@ func TestSelectLogsCreatedAfter(t *testing.T) { if len(topicVals) > 0 { exp := make([]query.Expression, len(topicVals)) for idx, val := range topicVals { - exp[idx] = logpoller.NewEventByTopicFilter(uint64(topicIdx), []primitives.ValueComparator{ - {Value: val.String(), Operator: primitives.Eq}, + exp[idx] = logpoller.NewEventByTopicFilter(uint64(topicIdx), []logpoller.HashedValueComparator{ + {Value: val, Operator: primitives.Eq}, }) } @@ -1955,11 +1955,11 @@ func TestSelectLogsDataWordBetween(t *testing.T) { Expressions: []query.Expression{ logpoller.NewAddressFilter(address), logpoller.NewEventSigFilter(eventSig), - logpoller.NewEventByWordFilter(eventSig, 0, []primitives.ValueComparator{ - {Value: logpoller.EvmWord(word).Hex(), Operator: primitives.Lte}, + logpoller.NewEventByWordFilter(0, []logpoller.HashedValueComparator{ + {Value: logpoller.EvmWord(word), Operator: primitives.Lte}, }), - logpoller.NewEventByWordFilter(eventSig, 1, []primitives.ValueComparator{ - {Value: logpoller.EvmWord(word).Hex(), Operator: primitives.Gte}, + logpoller.NewEventByWordFilter(1, []logpoller.HashedValueComparator{ + {Value: logpoller.EvmWord(word), Operator: primitives.Gte}, }), query.Confidence(primitives.Unconfirmed), }, diff --git a/core/chains/evm/logpoller/parser.go b/core/chains/evm/logpoller/parser.go index e08ea93da73..baa681e5efa 100644 --- a/core/chains/evm/logpoller/parser.go +++ b/core/chains/evm/logpoller/parser.go @@ -151,11 +151,11 @@ func (v *pgDSLParser) nestedConfQuery(finalized bool, confs uint64) string { } func (v *pgDSLParser) VisitEventByWordFilter(p *eventByWordFilter) { - if len(p.ValueComparers) > 0 { + if len(p.HashedValueComparers) > 0 { wordIdx := v.args.withIndexedField("word_index", p.WordIndex) - comps := make([]string, len(p.ValueComparers)) - for idx, comp := range p.ValueComparers { + comps := make([]string, len(p.HashedValueComparers)) + for idx, comp := range p.HashedValueComparers { comps[idx], v.err = makeComp(comp, v.args, "word_value", wordIdx, "substring(data from 32*:%s+1 for 32) %s :%s") if v.err != nil { return @@ -199,7 +199,7 @@ func (v *pgDSLParser) VisitConfirmationsFilter(p *confirmationsFilter) { } } -func makeComp(comp primitives.ValueComparator, args *queryArgs, field, subfield, pattern string) (string, error) { +func makeComp(comp HashedValueComparator, args *queryArgs, field, subfield, pattern string) (string, error) { cmp, err := cmpOpToString(comp.Operator) if err != nil { return "", err @@ -209,7 +209,7 @@ func makeComp(comp primitives.ValueComparator, args *queryArgs, field, subfield, pattern, subfield, cmp, - args.withIndexedField(field, common.HexToHash(comp.Value)), + args.withIndexedField(field, comp.Value), ), nil } @@ -492,17 +492,20 @@ func (f *eventSigFilter) Accept(visitor primitives.Visitor) { } } +type HashedValueComparator struct { + Value common.Hash + Operator primitives.ComparisonOperator +} + type eventByWordFilter struct { - EventSig common.Hash - WordIndex uint8 - ValueComparers []primitives.ValueComparator + WordIndex uint8 + HashedValueComparers []HashedValueComparator } -func NewEventByWordFilter(eventSig common.Hash, wordIndex uint8, valueComparers []primitives.ValueComparator) query.Expression { +func NewEventByWordFilter(wordIndex uint8, valueComparers []HashedValueComparator) query.Expression { return query.Expression{Primitive: &eventByWordFilter{ - EventSig: eventSig, - WordIndex: wordIndex, - ValueComparers: valueComparers, + WordIndex: wordIndex, + HashedValueComparers: valueComparers, }} } @@ -515,10 +518,10 @@ func (f *eventByWordFilter) Accept(visitor primitives.Visitor) { type eventByTopicFilter struct { Topic uint64 - ValueComparers []primitives.ValueComparator + ValueComparers []HashedValueComparator } -func NewEventByTopicFilter(topicIndex uint64, valueComparers []primitives.ValueComparator) query.Expression { +func NewEventByTopicFilter(topicIndex uint64, valueComparers []HashedValueComparator) query.Expression { return query.Expression{Primitive: &eventByTopicFilter{ Topic: topicIndex, ValueComparers: valueComparers, diff --git a/core/chains/evm/logpoller/parser_test.go b/core/chains/evm/logpoller/parser_test.go index 27af9e83188..f37497600bd 100644 --- a/core/chains/evm/logpoller/parser_test.go +++ b/core/chains/evm/logpoller/parser_test.go @@ -233,8 +233,8 @@ func TestDSLParser(t *testing.T) { t.Run("query for event by word", func(t *testing.T) { t.Parallel() - wordFilter := NewEventByWordFilter(common.HexToHash("0x42"), 8, []primitives.ValueComparator{ - {Value: "", Operator: primitives.Gt}, + wordFilter := NewEventByWordFilter(8, []HashedValueComparator{ + {Value: common.HexToHash(""), Operator: primitives.Gt}, }) parser := &pgDSLParser{} @@ -257,9 +257,9 @@ func TestDSLParser(t *testing.T) { t.Run("query for event topic", func(t *testing.T) { t.Parallel() - topicFilter := NewEventByTopicFilter(2, []primitives.ValueComparator{ - {Value: "a", Operator: primitives.Gt}, - {Value: "b", Operator: primitives.Lt}, + topicFilter := NewEventByTopicFilter(2, []HashedValueComparator{ + {Value: common.HexToHash("a"), Operator: primitives.Gt}, + {Value: common.HexToHash("b"), Operator: primitives.Lt}, }) parser := &pgDSLParser{} @@ -321,9 +321,9 @@ func TestDSLParser(t *testing.T) { t.Run("nested query deep", func(t *testing.T) { t.Parallel() - wordFilter := NewEventByWordFilter(common.HexToHash("0x42"), 8, []primitives.ValueComparator{ - {Value: "a", Operator: primitives.Gt}, - {Value: "b", Operator: primitives.Lte}, + wordFilter := NewEventByWordFilter(8, []HashedValueComparator{ + {Value: common.HexToHash("a"), Operator: primitives.Gt}, + {Value: common.HexToHash("b"), Operator: primitives.Lte}, }) parser := &pgDSLParser{} 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 c59a6f0f0d1..7adf4d8530a 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\"},{\"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", + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"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\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"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\":\"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\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"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: "0x608060405234801561001057600080fd5b50600180548082018255600082905260048082047fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6908101805460086003958616810261010090810a8088026001600160401b0391820219909416939093179093558654808801909755848704909301805496909516909202900a918202910219909216919091179055611a42806100a96000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c8063ab5e0b3811610081578063ef4e1ced1161005b578063ef4e1ced146101de578063f6f871c8146101e5578063fbe9fbf6146101f857600080fd5b8063ab5e0b381461019b578063dbfd7332146101b8578063dd1319b3146101cb57600080fd5b8063679004a4116100b2578063679004a41461012a5780636c9a43b61461013f578063a90e19981461018857600080fd5b80632c45576f146100d95780633272b66c1461010257806349eac2ac14610117575b600080fd5b6100ec6100e7366004610ca3565b61020a565b6040516100f99190610e0c565b60405180910390f35b610115610110366004610f4b565b6104e5565b005b610115610125366004611060565b61053a565b61013261083d565b6040516100f99190611152565b61011561014d3660046111a0565b600280547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff92909216919091179055565b6101156101963660046112d4565b6108c9565b6107c65b60405167ffffffffffffffff90911681526020016100f9565b6101156101c6366004611389565b610923565b6101156101d93660046113cc565b610960565b600361019f565b6100ec6101f3366004611060565b6109b7565b60025467ffffffffffffffff1661019f565b610212610ac0565b600061021f600184611471565b8154811061022f5761022f6114ab565b6000918252602091829020604080516101008101909152600a90920201805460030b8252600181018054929391929184019161026a906114da565b80601f0160208091040260200160405190810160405280929190818152602001828054610296906114da565b80156102e35780601f106102b8576101008083540402835291602001916102e3565b820191906000526020600020905b8154815290600101906020018083116102c657829003601f168201915b5050509183525050600282015460ff166020808301919091526040805161040081018083529190930192916003850191826000855b825461010083900a900460ff1681526020600192830181810494850194909303909202910180841161031857505050928452505050600482015473ffffffffffffffffffffffffffffffffffffffff1660208083019190915260058301805460408051828502810185018252828152940193928301828280156103d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116103a6575b5050509183525050600682015460170b6020808301919091526040805180820182526007808601805460f01b7fffff0000000000000000000000000000000000000000000000000000000000001683528351808501855260088801805490930b81526009880180549590970196939591948683019491939284019190610456906114da565b80601f0160208091040260200160405190810160405280929190818152602001828054610482906114da565b80156104cf5780601f106104a4576101008083540402835291602001916104cf565b820191906000526020600020905b8154815290600101906020018083116104b257829003601f168201915b5050509190925250505090525090525092915050565b81816040516104f5929190611527565b60405180910390207f3d969732b1bbbb9f1d7eb9f3f14e4cb50a74d950b3ef916a397b85dfbab93c67838360405161052e929190611580565b60405180910390a25050565b60006040518061010001604052808c60030b81526020018b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060ff8a166020808301919091526040805161040081810183529190930192918b9183908390808284376000920191909152505050815273ffffffffffffffffffffffffffffffffffffffff8816602080830191909152604080518883028181018401835289825291909301929189918991829190850190849080828437600092019190915250505090825250601785900b602082015260400161062c846115d6565b905281546001808201845560009384526020938490208351600a9093020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff90931692909217825592820151919290919082019061069290826116c3565b5060408201516002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff90921691909117905560608201516106e09060038301906020610b0f565b5060808201516004820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905560a08201518051610747916005840191602090910190610ba2565b5060c08201516006820180547fffffffffffffffff0000000000000000000000000000000000000000000000001677ffffffffffffffffffffffffffffffffffffffffffffffff90921691909117905560e082015180516007830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660f09290921c91909117815560208083015180516008860180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff90921691909117815591810151909190600986019061082a90826116c3565b5050505050505050505050505050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156108bf57602002820191906000526020600020906000905b82829054906101000a900467ffffffffffffffff1667ffffffffffffffff168152602001906008019060208260070104928301926001038202915080841161087a5790505b5050505050905090565b80826040516108d891906117dd565b6040518091039020846040516108ee9190611819565b604051908190038120907f7220e4dbe4e9d0ed5f71acd022bc89c26748ac6784f2c548bc17bb8e52af34b090600090a4505050565b8060030b8260030b8460030b7f91c80dc390f3d041b3a04b0099b19634499541ea26972250986ee4b24a12fac560405160405180910390a4505050565b8960030b7f4f01af651956288a9505cdb2c7565e925522cd4bb7e31f693f331357ec7b1b5f8a8a8a8a8a8a8a8a8a6040516109a39998979695949392919061197a565b60405180910390a250505050505050505050565b6109bf610ac0565b6040518061010001604052808c60030b81526020018b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060ff8a166020808301919091526040805161040081810183529190930192918b9183908390808284376000920191909152505050815273ffffffffffffffffffffffffffffffffffffffff8816602080830191909152604080518883028181018401835289825291909301929189918991829190850190849080828437600092019190915250505090825250601785900b6020820152604001610aaf846115d6565b90529b9a5050505050505050505050565b6040805161010081018252600080825260606020830181905292820152908101610ae8610c1c565b8152600060208201819052606060408301819052820152608001610b0a610c3b565b905290565b600183019183908215610b925791602002820160005b83821115610b6357835183826101000a81548160ff021916908360ff1602179055509260200192600101602081600001049283019260010302610b25565b8015610b905782816101000a81549060ff0219169055600101602081600001049283019260010302610b63565b505b50610b9e929150610c8e565b5090565b828054828255906000526020600020908101928215610b92579160200282015b82811115610b9257825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610bc2565b6040518061040001604052806020906020820280368337509192915050565b604051806040016040528060007dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001610b0a6040518060400160405280600060070b8152602001606081525090565b5b80821115610b9e5760008155600101610c8f565b600060208284031215610cb557600080fd5b5035919050565b60005b83811015610cd7578181015183820152602001610cbf565b50506000910152565b60008151808452610cf8816020860160208601610cbc565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8060005b6020808210610d3d5750610d54565b825160ff1685529384019390910190600101610d2e565b50505050565b600081518084526020808501945080840160005b83811015610da057815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101610d6e565b509495945050505050565b7fffff00000000000000000000000000000000000000000000000000000000000081511682526000602082015160406020850152805160070b60408501526020810151905060406060850152610e046080850182610ce0565b949350505050565b60208152610e2060208201835160030b9052565b600060208301516104e0806040850152610e3e610500850183610ce0565b91506040850151610e54606086018260ff169052565b506060850151610e676080860182610d2a565b50608085015173ffffffffffffffffffffffffffffffffffffffff1661048085015260a08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe085840381016104a0870152610ec48483610d5a565b935060c08701519150610edd6104c087018360170b9052565b60e0870151915080868503018387015250610ef88382610dab565b9695505050505050565b60008083601f840112610f1457600080fd5b50813567ffffffffffffffff811115610f2c57600080fd5b602083019150836020828501011115610f4457600080fd5b9250929050565b60008060208385031215610f5e57600080fd5b823567ffffffffffffffff811115610f7557600080fd5b610f8185828601610f02565b90969095509350505050565b8035600381900b8114610f9f57600080fd5b919050565b803560ff81168114610f9f57600080fd5b806104008101831015610fc757600080fd5b92915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610f9f57600080fd5b60008083601f84011261100357600080fd5b50813567ffffffffffffffff81111561101b57600080fd5b6020830191508360208260051b8501011115610f4457600080fd5b8035601781900b8114610f9f57600080fd5b60006040828403121561105a57600080fd5b50919050565b6000806000806000806000806000806104e08b8d03121561108057600080fd5b6110898b610f8d565b995060208b013567ffffffffffffffff808211156110a657600080fd5b6110b28e838f01610f02565b909b5099508991506110c660408e01610fa4565b98506110d58e60608f01610fb5565b97506110e46104608e01610fcd565b96506104808d01359150808211156110fb57600080fd5b6111078e838f01610ff1565b909650945084915061111c6104a08e01611036565b93506104c08d013591508082111561113357600080fd5b506111408d828e01611048565b9150509295989b9194979a5092959850565b6020808252825182820181905260009190848201906040850190845b8181101561119457835167ffffffffffffffff168352928401929184019160010161116e565b50909695505050505050565b6000602082840312156111b257600080fd5b813567ffffffffffffffff811681146111ca57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611223576112236111d1565b60405290565b600082601f83011261123a57600080fd5b813567ffffffffffffffff80821115611255576112556111d1565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561129b5761129b6111d1565b816040528381528660208588010111156112b457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600061044084860312156112ea57600080fd5b833567ffffffffffffffff8082111561130257600080fd5b61130e87838801611229565b94506020915086603f87011261132357600080fd5b6040516104008101818110838211171561133f5761133f6111d1565b60405290508061042087018881111561135757600080fd5b8388015b818110156113795761136c81610fa4565b845292840192840161135b565b5095989097509435955050505050565b60008060006060848603121561139e57600080fd5b6113a784610f8d565b92506113b560208501610f8d565b91506113c360408501610f8d565b90509250925092565b6000806000806000806000806000806104e08b8d0312156113ec57600080fd5b6113f58b610f8d565b995061140360208c01610fa4565b98506114128c60408d01610fb5565b97506114216104408c01610fcd565b96506104608b013567ffffffffffffffff8082111561143f57600080fd5b61144b8e838f01610ff1565b90985096506104808d013591508082111561146557600080fd5b6111078e838f01610f02565b81810381811115610fc7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c908216806114ee57607f821691505b60208210810361105a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000610e04602083018486611537565b80357fffff00000000000000000000000000000000000000000000000000000000000081168114610f9f57600080fd5b8035600781900b8114610f9f57600080fd5b6000604082360312156115e857600080fd5b6115f0611200565b6115f983611594565b8152602083013567ffffffffffffffff8082111561161657600080fd5b81850191506040823603121561162b57600080fd5b611633611200565b61163c836115c4565b815260208301358281111561165057600080fd5b61165c36828601611229565b60208301525080602085015250505080915050919050565b601f8211156116be57600081815260208120601f850160051c8101602086101561169b5750805b601f850160051c820191505b818110156116ba578281556001016116a7565b5050505b505050565b815167ffffffffffffffff8111156116dd576116dd6111d1565b6116f1816116eb84546114da565b84611674565b602080601f831160018114611744576000841561170e5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556116ba565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561179157888601518255948401946001909101908401611772565b50858210156117cd57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60008183825b60208082106117f25750611809565b825160ff16845292830192909101906001016117e3565b5050506104008201905092915050565b6000825161182b818460208701610cbc565b9190910192915050565b8183526000602080850194508260005b85811015610da05773ffffffffffffffffffffffffffffffffffffffff61186b83610fcd565b1687529582019590820190600101611845565b7fffff0000000000000000000000000000000000000000000000000000000000006118a882611594565b168252600060208201357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126118e257600080fd5b6040602085015282016118f4816115c4565b60070b604085015260208101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe182360301811261193157600080fd5b0160208101903567ffffffffffffffff81111561194d57600080fd5b80360382131561195c57600080fd5b60406060860152611971608086018284611537565b95945050505050565b60006104c060ff808d16845260208085018d60005b838110156119b457846119a183610fa4565b168352918301919083019060010161198f565b505050505073ffffffffffffffffffffffffffffffffffffffff8a16610420840152806104408401526119ea818401898b611835565b9050828103610460840152611a00818789611537565b9050611a1261048084018660170b9052565b8281036104a0840152611a25818561187e565b9c9b50505050505050505050505056fea164736f6c6343000813000a", } var ChainReaderTesterABI = ChainReaderTesterMetaData.ABI @@ -348,16 +348,16 @@ func (_ChainReaderTester *ChainReaderTesterTransactorSession) SetAlterablePrimit return _ChainReaderTester.Contract.SetAlterablePrimitiveValue(&_ChainReaderTester.TransactOpts, value) } -func (_ChainReaderTester *ChainReaderTesterTransactor) TriggerEvent(opts *bind.TransactOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { - return _ChainReaderTester.contract.Transact(opts, "triggerEvent", field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +func (_ChainReaderTester *ChainReaderTesterTransactor) TriggerEvent(opts *bind.TransactOpts, field int32, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, differentField string, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _ChainReaderTester.contract.Transact(opts, "triggerEvent", field, oracleId, oracleIds, account, accounts, differentField, bigField, nestedStruct) } -func (_ChainReaderTester *ChainReaderTesterSession) TriggerEvent(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { - return _ChainReaderTester.Contract.TriggerEvent(&_ChainReaderTester.TransactOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +func (_ChainReaderTester *ChainReaderTesterSession) TriggerEvent(field int32, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, differentField string, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _ChainReaderTester.Contract.TriggerEvent(&_ChainReaderTester.TransactOpts, field, oracleId, oracleIds, account, accounts, differentField, bigField, nestedStruct) } -func (_ChainReaderTester *ChainReaderTesterTransactorSession) TriggerEvent(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { - return _ChainReaderTester.Contract.TriggerEvent(&_ChainReaderTester.TransactOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +func (_ChainReaderTester *ChainReaderTesterTransactorSession) TriggerEvent(field int32, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, differentField string, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _ChainReaderTester.Contract.TriggerEvent(&_ChainReaderTester.TransactOpts, field, oracleId, oracleIds, account, accounts, differentField, bigField, nestedStruct) } func (_ChainReaderTester *ChainReaderTesterTransactor) TriggerEventWithDynamicTopic(opts *bind.TransactOpts, field string) (*types.Transaction, error) { @@ -458,11 +458,11 @@ func (it *ChainReaderTesterTriggeredIterator) Close() error { type ChainReaderTesterTriggered struct { Field int32 - DifferentField string OracleId uint8 OracleIds [32]uint8 Account common.Address Accounts []common.Address + DifferentField string BigField *big.Int NestedStruct MidLevelTestStruct Raw types.Log @@ -965,7 +965,7 @@ func (_ChainReaderTester *ChainReaderTester) ParseLog(log types.Log) (generated. } func (ChainReaderTesterTriggered) Topic() common.Hash { - return common.HexToHash("0x7188419dcd8b51877b71766f075f3626586c0ff190e7d056aa65ce9acb649a3d") + return common.HexToHash("0x4f01af651956288a9505cdb2c7565e925522cd4bb7e31f693f331357ec7b1b5f") } func (ChainReaderTesterTriggeredEventWithDynamicTopic) Topic() common.Hash { @@ -1001,7 +1001,7 @@ type ChainReaderTesterInterface interface { SetAlterablePrimitiveValue(opts *bind.TransactOpts, value uint64) (*types.Transaction, error) - TriggerEvent(opts *bind.TransactOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) + TriggerEvent(opts *bind.TransactOpts, field int32, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, differentField string, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) TriggerEventWithDynamicTopic(opts *bind.TransactOpts, field string) (*types.Transaction, error) diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index fe6437f48c6..18acf5fc30f 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 @@ -24,7 +24,7 @@ batch_vrf_coordinator_v2: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/Batc 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 7a82cc28014761090185c2650239ad01a0901181f1b2b899b42ca293bcda3741 -chain_reader_tester: ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.abi ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.bin b207f9e6bf71e445a2664a602677011b87b80bf95c6352fd7869f1a9ddb08a5b +chain_reader_tester: ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.abi ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.bin 84c4223c4dbd51aafd77a6787f4b84ce80f661ce86a907c1431c5b82d633f2ad 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 diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 59e032565f5..720ceec8d12 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -22,7 +22,7 @@ require ( github.com/prometheus/client_golang v1.20.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.20240916150342-36cb47701edf + github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 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.1 @@ -116,7 +116,7 @@ require ( github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/esote/minmaxheap v1.0.0 // indirect github.com/ethereum/c-kzg-4844 v0.4.0 // indirect - github.com/fatih/color v1.16.0 // indirect + github.com/fatih/color v1.17.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect @@ -341,8 +341,8 @@ require ( go.uber.org/zap v1.27.0 // indirect golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.27.0 // indirect - golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect - golang.org/x/mod v0.20.0 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect + golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect golang.org/x/sync v0.8.0 // indirect @@ -350,7 +350,7 @@ require ( golang.org/x/term v0.24.0 // indirect golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.6.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/tools v0.25.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-20240822170219-fc7c04adadcd // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 8cd12f5e426..6684beddc94 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -357,8 +357,8 @@ github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+ne github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= @@ -1083,8 +1083,8 @@ github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8um github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612 h1:xPEM9XbfZmv8N3NjZ7AX5salonll/LdXrbb8JCbA4FE= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612/go.mod h1:Lv77O13ZxOdmlvnu2vaUC0Lg+t3JAL+N+9K8dRsgmDI= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240916150342-36cb47701edf h1:1AlTUkT5D8HmvU9bwDoIN54/EFyOnRBl7gnXZVrYXEA= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240916150342-36cb47701edf/go.mod h1:l8NTByXUdGGJX+vyKYI6yX1/HIpM14F8Wm9BkU3Q4Qo= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 h1:wqLXuPdiUkn7es/epKmOpB0Q0tKdA9FkYPNQZrZ+VJU= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06/go.mod h1:zm+l8gN4LQS1+YvwQDhRz/njirVeWGNiDJKIhCGwaoQ= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7/go.mod h1:BMYE1vC/pGmdFSsOJdPrAA0/4gZ0Xo0SxTMdGspBtRo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 h1:yRk4ektpx/UxwarqAfgxUXLrsYXlaNeP1NOwzHGrK2Q= @@ -1376,8 +1376,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-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= -golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= 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= @@ -1402,8 +1402,8 @@ golang.org/x/mod v0.3.0/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.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -1614,8 +1614,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 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.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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/services/relay/evm/chain_components_test.go b/core/services/relay/evm/chain_components_test.go index 841e2d0a7e0..50c530904dd 100644 --- a/core/services/relay/evm/chain_components_test.go +++ b/core/services/relay/evm/chain_components_test.go @@ -20,8 +20,8 @@ import ( "github.com/stretchr/testify/require" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + commontestutils "github.com/smartcontractkit/chainlink-common/pkg/loop/testutils" clcommontypes "github.com/smartcontractkit/chainlink-common/pkg/types" - . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -29,8 +29,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" - commontestutils "github.com/smartcontractkit/chainlink-common/pkg/loop/testutils" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -159,7 +157,7 @@ func TestChainComponents(t *testing.T) { // add new subtests here so that it can be run on real chains too RunChainComponentsEvmTests(t, it) - RunContractReaderInterfaceTests[*testing.T](t, commontestutils.WrapContractReaderTesterForLoop(it), false) + RunChainComponentsInLoopEvmTests[*testing.T](t, commontestutils.WrapContractReaderTesterForLoop(it)) } type helper struct { diff --git a/core/services/relay/evm/chain_reader.go b/core/services/relay/evm/chain_reader.go index 800631b858d..f4d464f6585 100644 --- a/core/services/relay/evm/chain_reader.go +++ b/core/services/relay/evm/chain_reader.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "maps" "reflect" "slices" "strings" @@ -50,7 +51,7 @@ var _ commontypes.ContractTypeProvider = &chainReader{} // NewChainReaderService is a constructor for ChainReader, returns nil if there is any error // 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) { +func NewChainReaderService(_ context.Context, lggr logger.Logger, lp logpoller.LogPoller, ht logpoller.HeadTracker, client evmclient.Client, config types.ChainReaderConfig) (ChainReaderService, error) { cr := &chainReader{ lggr: logger.Named(lggr, "ChainReader"), ht: ht, @@ -131,7 +132,7 @@ func (cr *chainReader) init(chainContractReaders map[string]types.ChainContractR return fmt.Errorf("%w: no read bindings added for contract: %s", commontypes.ErrInvalidConfig, contractName) } - if err := cr.bindings.SetFilter(contractName, chainContractReader.PollingFilter.ToLPFilter(eventSigsForContractFilter)); err != nil { + if err = cr.bindings.SetFilter(contractName, chainContractReader.PollingFilter.ToLPFilter(eventSigsForContractFilter)); err != nil { return err } } @@ -152,7 +153,6 @@ func (cr *chainReader) Close() error { return cr.StopOnce("ChainReader", func() error { ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() - return cr.bindings.UnregisterAll(ctx, cr.lp) }) } @@ -163,6 +163,14 @@ func (cr *chainReader) HealthReport() map[string]error { return map[string]error{cr.Name(): nil} } +func (cr *chainReader) Bind(ctx context.Context, bindings []commontypes.BoundContract) error { + return cr.bindings.Bind(ctx, cr.lp, bindings) +} + +func (cr *chainReader) Unbind(ctx context.Context, bindings []commontypes.BoundContract) error { + return cr.bindings.Unbind(ctx, cr.lp, bindings) +} + func (cr *chainReader) GetLatestValue(ctx context.Context, readName string, confidenceLevel primitives.ConfidenceLevel, params any, returnVal any) error { binding, address, err := cr.bindings.GetReader(readName) if err != nil { @@ -176,14 +184,6 @@ func (cr *chainReader) BatchGetLatestValues(ctx context.Context, request commont return cr.bindings.BatchGetLatestValues(ctx, request) } -func (cr *chainReader) Bind(ctx context.Context, bindings []commontypes.BoundContract) error { - return cr.bindings.Bind(ctx, cr.lp, bindings) -} - -func (cr *chainReader) Unbind(ctx context.Context, bindings []commontypes.BoundContract) error { - return cr.bindings.Unbind(ctx, cr.lp, bindings) -} - func (cr *chainReader) QueryKey( ctx context.Context, contract commontypes.BoundContract, @@ -203,13 +203,6 @@ func (cr *chainReader) CreateContractType(readIdentifier string, forEncoding boo return cr.codec.CreateType(cr.bindings.ReadTypeIdentifier(readIdentifier, forEncoding), forEncoding) } -func WrapItemType(contractName, itemType string, isParams bool) string { - if isParams { - return fmt.Sprintf("params.%s.%s", contractName, itemType) - } - return fmt.Sprintf("return.%s.%s", contractName, itemType) -} - func (cr *chainReader) addMethod( contractName, methodName string, @@ -225,9 +218,11 @@ func (cr *chainReader) addMethod( return err } - cr.bindings.AddReader(contractName, methodName, read.NewMethodBinding(contractName, methodName, cr.client, cr.ht, confirmations, cr.lggr)) + if err = cr.bindings.AddReader(contractName, methodName, read.NewMethodBinding(contractName, methodName, cr.client, cr.ht, confirmations, cr.lggr)); err != nil { + return err + } - if err := cr.addEncoderDef(contractName, methodName, method.Inputs, method.ID, chainReaderDefinition.InputModifications); err != nil { + if err = cr.addEncoderDef(contractName, methodName, method.Inputs, method.ID, chainReaderDefinition.InputModifications); err != nil { return err } @@ -240,26 +235,20 @@ func (cr *chainReader) addEvent(contractName, eventName string, a abi.ABI, chain return fmt.Errorf("%w: event %s doesn't exist", commontypes.ErrInvalidConfig, chainReaderDefinition.ChainSpecificName) } - var inputFields []string - if chainReaderDefinition.EventDefinitions != nil { - inputFields = chainReaderDefinition.EventDefinitions.InputFields - } - - filterArgs, codecTopicInfo, indexArgNames := setupEventInput(event, inputFields) - if err := verifyEventIndexedInputsUsed(eventName, inputFields, indexArgNames); err != nil { - return err - } - - if err := codecTopicInfo.Init(); err != nil { + indexedAsUnIndexedABITypes, indexedTopicsCodecTypes, eventDWs := getEventTypes(event) + if err := indexedTopicsCodecTypes.Init(); err != nil { return err } // 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 { + err := cr.addEncoderDef(contractName, eventName, indexedAsUnIndexedABITypes, nil, chainReaderDefinition.InputModifications) + if err != nil { return err } - inputInfo, inputModifier, err := cr.getEventInput(chainReaderDefinition, contractName, eventName) + codecTypes, codecModifiers := make(map[string]types.CodecEntry), make(map[string]commoncodec.Modifier) + topicTypeID := codec.WrapItemType(contractName, eventName, true) + codecTypes[topicTypeID], codecModifiers[topicTypeID], err = cr.getEventItemTypeAndModifier(topicTypeID, chainReaderDefinition.InputModifications) if err != nil { return err } @@ -269,59 +258,113 @@ func (cr *chainReader) addEvent(contractName, eventName string, a abi.ABI, chain return err } - eb := read.NewEventBinding(contractName, eventName, cr.lp, event.ID, inputInfo, inputModifier, codecTopicInfo, confirmations) + eb := read.NewEventBinding(contractName, eventName, cr.lp, event.ID, indexedTopicsCodecTypes, confirmations) if eventDefinitions := chainReaderDefinition.EventDefinitions; eventDefinitions != nil { if eventDefinitions.PollingFilter != nil { eb.SetFilter(eventDefinitions.PollingFilter.ToLPFilter(evmtypes.HashArray{a.Events[event.Name].ID})) } - if eventDefinitions.GenericDataWordNames != nil { - eb.SetDataWords(eventDefinitions.GenericDataWordNames) + topicsDetails, topicsCodecTypeInfo, topicsModifiers, initQueryingErr := cr.initTopicQuerying(contractName, eventName, event.Inputs, eventDefinitions.GenericTopicNames, chainReaderDefinition.InputModifications) + if initQueryingErr != nil { + return initQueryingErr } + maps.Copy(codecTypes, topicsCodecTypeInfo) + // TODO BCFR-44 reused GetLatestValue params modifiers, probably can be left like this + maps.Copy(codecModifiers, topicsModifiers) + + // TODO BCFR-44 no dw modifier for now + dataWordsDetails, dWSCodecTypeInfo, initDWQueryingErr := cr.initDWQuerying(contractName, eventName, eventDWs, eventDefinitions.GenericDataWordNames) + if initDWQueryingErr != nil { + return initDWQueryingErr + } + maps.Copy(codecTypes, dWSCodecTypeInfo) - cr.addQueryingReadBindings(contractName, eventDefinitions.GenericTopicNames, event.Inputs, eb) + eb.SetTopicDetails(topicsDetails) + eb.SetDataWordsDetails(dataWordsDetails) } - cr.bindings.AddReader(contractName, eventName, eb) + eb.SetCodecTypesAndModifiers(codecTypes, codecModifiers) + if err = cr.bindings.AddReader(contractName, eventName, eb); err != nil { + return err + } return cr.addDecoderDef(contractName, eventName, event.Inputs, chainReaderDefinition.OutputModifications) } -// addQueryingReadBindings reuses the eventBinding and maps it to topic and dataWord keys used for QueryKey. -func (cr *chainReader) addQueryingReadBindings(contractName string, genericTopicNames map[string]string, eventInputs abi.Arguments, eb *read.EventBinding) { - // add topic readBindings for QueryKey +// initTopicQuerying registers codec types and modifiers for topics to be used for typing value comparator QueryKey filters. +func (cr *chainReader) initTopicQuerying(contractName, eventName string, eventInputs abi.Arguments, genericTopicNames map[string]string, inputModifications commoncodec.ModifiersConfig) (map[string]read.TopicDetail, map[string]types.CodecEntry, map[string]commoncodec.Modifier, error) { + topicsDetails := make(map[string]read.TopicDetail) + topicsTypes := make(map[string]types.CodecEntry) + topicsModifiers := make(map[string]commoncodec.Modifier) for topicIndex, topic := range eventInputs { genericTopicName, ok := genericTopicNames[topic.Name] if ok { - eb.WithTopic(genericTopicName, topic, uint64(topicIndex)) - } + // Encoder defs codec won't be used for encoding, but for storing caller filtering params which won't be hashed. + topicTypeID := eventName + "." + genericTopicName + err := cr.addEncoderDef(contractName, topicTypeID, abi.Arguments{{Type: topic.Type}}, nil, inputModifications) + if err != nil { + return nil, nil, nil, err + } - cr.bindings.AddReader(contractName, genericTopicName, eb) - } + topicTypeID = codec.WrapItemType(contractName, topicTypeID, true) + topicsTypes[topicTypeID], topicsModifiers[topicTypeID], err = cr.getEventItemTypeAndModifier(topicTypeID, inputModifications) + if err != nil { + return nil, nil, nil, err + } - // add data word readBindings for QueryKey - for genericDataWordName := range eb.GetDataWords() { - cr.bindings.AddReader(contractName, genericDataWordName, eb) + topicsDetails[genericTopicName] = read.TopicDetail{Argument: topic, Index: uint64(topicIndex + 1)} + } } + return topicsDetails, topicsTypes, topicsModifiers, nil } -// 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, commoncodec.Modifier, error) { - inputInfo := cr.parsed.EncoderDefs[WrapItemType(contractName, eventName, true)] +// initDWQuerying registers codec types for evm data words to be used for typing value comparator QueryKey filters. +func (cr *chainReader) initDWQuerying(contractName, eventName string, eventDWs map[string]read.DataWordDetail, dWDefs map[string]string) (map[string]read.DataWordDetail, map[string]types.CodecEntry, error) { + dwsCodecTypeInfo := make(map[string]types.CodecEntry) + dWsDetail := make(map[string]read.DataWordDetail) + + for genericName, onChainName := range dWDefs { + foundDW := false + for _, dWDetail := range eventDWs { + if dWDetail.Name != onChainName { + continue + } + + foundDW = true + + dwTypeID := eventName + "." + genericName + if err := cr.addEncoderDef(contractName, dwTypeID, abi.Arguments{abi.Argument{Type: dWDetail.Type}}, nil, nil); err != nil { + return nil, nil, fmt.Errorf("%w: failed to init codec for data word %s on index %d querying for event: %q", err, genericName, dWDetail.Index, eventName) + } - // TODO can this be simplified? Isn't this same as inputInfo.Modifier()? BCI-3909 - inMod, err := def.InputModifications.ToModifier(codec.DecoderHooks...) + dwCodecTypeID := codec.WrapItemType(contractName, dwTypeID, true) + dwsCodecTypeInfo[dwCodecTypeID] = cr.parsed.EncoderDefs[dwCodecTypeID] + + dWsDetail[genericName] = dWDetail + break + } + if !foundDW { + return nil, nil, fmt.Errorf("failed to find data word: %q for event: %q, its either out of bounds or can't be searched for", genericName, eventName) + } + } + return dWsDetail, dwsCodecTypeInfo, nil +} + +// getEventItemTypeAndModifier returns codec entry for expected incoming event item and the modifier. +func (cr *chainReader) getEventItemTypeAndModifier(itemType string, inputMod commoncodec.ModifiersConfig) (types.CodecEntry, commoncodec.Modifier, error) { + inputTypeInfo := cr.parsed.EncoderDefs[itemType] + // TODO can this be simplified? Isn't this same as inputType.Modifier()? BCI-3909 + inMod, err := inputMod.ToModifier(codec.DecoderHooks...) if err != nil { return nil, nil, err } // initialize the modification - if _, err = inMod.RetypeToOffChain(reflect.PointerTo(inputInfo.CheckedType()), ""); err != nil { + if _, err = inMod.RetypeToOffChain(reflect.PointerTo(inputTypeInfo.CheckedType()), ""); err != nil { return nil, nil, err } - return inputInfo, inMod, nil + return inputTypeInfo, inMod, nil } func (cr *chainReader) addEncoderDef(contractName, itemType string, args abi.Arguments, prefix []byte, inputModifications commoncodec.ModifiersConfig) error { @@ -336,7 +379,7 @@ func (cr *chainReader) addEncoderDef(contractName, itemType string, args abi.Arg return err } - cr.parsed.EncoderDefs[WrapItemType(contractName, itemType, true)] = input + cr.parsed.EncoderDefs[codec.WrapItemType(contractName, itemType, true)] = input return nil } @@ -346,52 +389,46 @@ func (cr *chainReader) addDecoderDef(contractName, itemType string, outputs abi. return err } output := types.NewCodecEntry(outputs, nil, mod) - cr.parsed.DecoderDefs[read.WrapItemType(contractName, itemType, false)] = output + cr.parsed.DecoderDefs[codec.WrapItemType(contractName, itemType, false)] = output return output.Init() } -func verifyEventIndexedInputsUsed(eventName string, inputFields []string, indexArgNames map[string]bool) error { - for _, value := range inputFields { - if !indexArgNames[abi.ToCamelCase(value)] { - return fmt.Errorf("%w: %s is not an indexed argument of event %s", commontypes.ErrInvalidConfig, value, eventName) - } - } - return nil -} - -// 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 { - capFirstValue := abi.ToCamelCase(value) - topicFieldDefs[capFirstValue] = true - } - - filterArgs := make([]abi.Argument, 0, types.MaxTopicFields) - inputArgs := make([]abi.Argument, 0, len(event.Inputs)) - indexArgNames := map[string]bool{} +// getEventTypes returns abi args where indexed flag is set to false because we expect caller to filter with params that aren't hashed, +// codecEntry where expected on chain types are set, for e.g. indexed topics of type string or uint8[32] array are expected as common.Hash onchain, +// and un-indexed data info in form of evm indexed 32 byte data words. +func getEventTypes(event abi.Event) ([]abi.Argument, types.CodecEntry, map[string]read.DataWordDetail) { + indexedAsUnIndexedTypes := make([]abi.Argument, 0, types.MaxTopicFields) + indexedTypes := make([]abi.Argument, 0, len(event.Inputs)) + dataWords := make(map[string]read.DataWordDetail) + hadDynamicType := false + var dwIndex uint8 for _, input := range event.Inputs { if !input.Indexed { - continue - } + // there are some cases where we can calculate the exact data word index even if there was a dynamic type before, but it is complex and probably not needed. + if input.Type.T == abi.TupleTy || input.Type.T == abi.SliceTy || input.Type.T == abi.StringTy || input.Type.T == abi.BytesTy { + hadDynamicType = true + } + if hadDynamicType { + continue + } - filterWith := topicFieldDefs[abi.ToCamelCase(input.Name)] - if filterWith { - // When presenting the filter off-chain, - // the user will provide the unhashed version of the input - // The reader will hash topics if needed. - inputUnindexed := input - inputUnindexed.Indexed = false - filterArgs = append(filterArgs, inputUnindexed) + dataWords[event.Name+"."+input.Name] = read.DataWordDetail{ + Index: dwIndex, + Argument: input, + } + dwIndex++ + continue } - inputArgs = append(inputArgs, input) - indexArgNames[abi.ToCamelCase(input.Name)] = true + indexedAsUnIndexed := input + indexedAsUnIndexed.Indexed = false + // when presenting the filter off-chain, the caller will provide the unHashed version of the input and CR will hash topics when needed. + indexedAsUnIndexedTypes = append(indexedAsUnIndexedTypes, indexedAsUnIndexed) + indexedTypes = append(indexedTypes, input) } - return filterArgs, types.NewCodecEntry(inputArgs, nil, nil), indexArgNames + return indexedAsUnIndexedTypes, types.NewCodecEntry(indexedTypes, nil, nil), dataWords } // ConfirmationsFromConfig maps chain agnostic confidence levels defined in config to predefined EVM finality. diff --git a/core/services/relay/evm/chain_reader_historical_client_wrapper_test.go b/core/services/relay/evm/chain_reader_historical_client_wrapper_test.go index 6779b5d0209..28984779c36 100644 --- a/core/services/relay/evm/chain_reader_historical_client_wrapper_test.go +++ b/core/services/relay/evm/chain_reader_historical_client_wrapper_test.go @@ -18,7 +18,6 @@ import ( "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/relay/evm/codec" - "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/read" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) @@ -69,8 +68,8 @@ func (cwh *ClientWithContractHistory) Init(_ context.Context, config types.Chain return err } - parsedTypes.EncoderDefs[read.WrapItemType(contractName, genericName, true)] = input - parsedTypes.DecoderDefs[read.WrapItemType(contractName, genericName, false)] = output + parsedTypes.EncoderDefs[codec.WrapItemType(contractName, genericName, true)] = input + parsedTypes.DecoderDefs[codec.WrapItemType(contractName, genericName, false)] = output } } @@ -126,7 +125,7 @@ func (cwh *ClientWithContractHistory) CallContract(ctx context.Context, msg ethe } // encode the expected call to compare with the actual call - dataToCmp, err := cwh.codec.Encode(ctx, valAndCall.Params, read.WrapItemType(valAndCall.ContractName, valAndCall.ReadName, true)) + dataToCmp, err := cwh.codec.Encode(ctx, valAndCall.Params, codec.WrapItemType(valAndCall.ContractName, valAndCall.ReadName, true)) if err != nil { return nil, err } diff --git a/core/services/relay/evm/chain_writer.go b/core/services/relay/evm/chain_writer.go index fddd865dbbe..d61c17b2ae2 100644 --- a/core/services/relay/evm/chain_writer.go +++ b/core/services/relay/evm/chain_writer.go @@ -101,7 +101,7 @@ func (w *chainWriter) SubmitTransaction(ctx context.Context, contract, method st return fmt.Errorf("method config not found: %v", method) } - calldata, err := w.encoder.Encode(ctx, args, WrapItemType(contract, method, true)) + calldata, err := w.encoder.Encode(ctx, args, codec.WrapItemType(contract, method, true)) if err != nil { return fmt.Errorf("%w: failed to encode args", err) } @@ -173,7 +173,7 @@ func (w *chainWriter) parseContracts() error { return fmt.Errorf("%w: failed to init codec entry for method %s", err, method) } - w.parsedContracts.EncoderDefs[WrapItemType(contract, method, true)] = input + w.parsedContracts.EncoderDefs[codec.WrapItemType(contract, method, true)] = input } } diff --git a/core/services/relay/evm/codec/codec.go b/core/services/relay/evm/codec/codec.go index 5cd606755ca..3a859c89a8b 100644 --- a/core/services/relay/evm/codec/codec.go +++ b/core/services/relay/evm/codec/codec.go @@ -96,6 +96,14 @@ func (c *evmCodec) CreateType(itemType string, forEncoding bool) (any, error) { return reflect.New(def.CheckedType()).Interface(), nil } +func WrapItemType(contractName, itemType string, isParams bool) string { + if isParams { + return fmt.Sprintf("params.%s.%s", contractName, itemType) + } + + return fmt.Sprintf("return.%s.%s", contractName, itemType) +} + var bigIntType = reflect.TypeOf((*big.Int)(nil)) func sizeVerifyBigIntHook(from, to reflect.Type, data any) (any, error) { diff --git a/core/services/relay/evm/evmtesting/chain_components_interface_tester.go b/core/services/relay/evm/evmtesting/chain_components_interface_tester.go index facef2bb7e6..df34d63fc42 100644 --- a/core/services/relay/evm/evmtesting/chain_components_interface_tester.go +++ b/core/services/relay/evm/evmtesting/chain_components_interface_tester.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/codec" clcommontypes "github.com/smartcontractkit/chainlink-common/pkg/types" . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . - primitives "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" + "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -135,6 +135,10 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { EventName: { ChainSpecificName: "Triggered", ReadType: types.Event, + EventDefinitions: &types.EventDefinitions{ + GenericTopicNames: map[string]string{"field": "Field"}, + GenericDataWordNames: map[string]string{"OracleID": "oracleId"}, + }, OutputModifications: codec.ModifiersConfig{ &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, }, @@ -142,13 +146,11 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { EventWithFilterName: { ChainSpecificName: "Triggered", ReadType: types.Event, - EventDefinitions: &types.EventDefinitions{InputFields: []string{"Field"}}, }, triggerWithDynamicTopic: { ChainSpecificName: triggerWithDynamicTopic, ReadType: types.Event, EventDefinitions: &types.EventDefinitions{ - InputFields: []string{"fieldHash"}, // No specific reason for filter being defined here instead of on contract level, this is just for test case variety. PollingFilter: &types.PollingFilter{}, }, @@ -160,7 +162,6 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { ChainSpecificName: triggerWithAllTopics, ReadType: types.Event, EventDefinitions: &types.EventDefinitions{ - InputFields: []string{"Field1", "Field2", "Field3"}, PollingFilter: &types.PollingFilter{}, }, // This doesn't have to be here, since the defalt mapping would work, but is left as an example. @@ -171,9 +172,7 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { triggerWithAllTopicsWithHashed: { ChainSpecificName: triggerWithAllTopicsWithHashed, ReadType: types.Event, - EventDefinitions: &types.EventDefinitions{ - InputFields: []string{"Field1", "Field2", "Field3"}, - }, + EventDefinitions: &types.EventDefinitions{}, }, MethodReturningSeenStruct: { ChainSpecificName: "returnSeen", diff --git a/core/services/relay/evm/evmtesting/run_tests.go b/core/services/relay/evm/evmtesting/run_tests.go index cb68a1b8870..c999693de50 100644 --- a/core/services/relay/evm/evmtesting/run_tests.go +++ b/core/services/relay/evm/evmtesting/run_tests.go @@ -12,7 +12,9 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" clcommontypes "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-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/read" . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . @@ -23,6 +25,11 @@ func RunChainComponentsEvmTests[T TestingT[T]](t T, it *EVMChainComponentsInterf // Add ChainWriter tests here } +func RunChainComponentsInLoopEvmTests[T TestingT[T]](t T, it ChainComponentsInterfaceTester[T]) { + RunContractReaderInLoopTests[T](t, it) + // Add ChainWriter tests here +} + func RunContractReaderEvmTests[T TestingT[T]](t T, it *EVMChainComponentsInterfaceTester[T]) { RunContractReaderInterfaceTests[T](t, it, false) @@ -142,6 +149,41 @@ func RunContractReaderEvmTests[T TestingT[T]](t T, it *EVMChainComponentsInterfa }) } +func RunContractReaderInLoopTests[T TestingT[T]](t T, it ChainComponentsInterfaceTester[T]) { + RunContractReaderInterfaceTests[T](t, it, false) + + t.Run("Filtering can be done on data words using value comparator", func(t T) { + it.Setup(t) + + ctx := tests.Context(t) + cr := it.GetContractReader(t) + require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) + bindings := it.GetBindings(t) + boundContract := BindingsByName(bindings, AnyContractName)[0] + require.NoError(t, cr.Bind(ctx, bindings)) + + ts1 := CreateTestStruct[T](0, it) + _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts1, boundContract, types.Unconfirmed) + ts2 := CreateTestStruct[T](15, it) + _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts2, boundContract, types.Unconfirmed) + ts3 := CreateTestStruct[T](35, it) + _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts3, boundContract, types.Unconfirmed) + + ts := &TestStruct{} + assert.Eventually(t, func() bool { + sequences, err := cr.QueryKey(ctx, boundContract, query.KeyFilter{Key: EventName, Expressions: []query.Expression{ + query.Comparator("OracleID", + primitives.ValueComparator{ + Value: uint8(ts2.OracleID), + Operator: primitives.Eq, + }), + }, + }, query.LimitAndSort{}, ts) + return err == nil && len(sequences) == 1 && reflect.DeepEqual(&ts2, sequences[0].Data) + }, it.MaxWaitTimeForEvents(), time.Millisecond*10) + }) +} + func triggerFourTopics[T TestingT[T]](t T, it *EVMChainComponentsInterfaceTester[T], i1, i2, i3 int32) { type DynamicEvent struct { Field1 int32 diff --git a/core/services/relay/evm/read/batch.go b/core/services/relay/evm/read/batch.go index 412d9a11383..1d72e222963 100644 --- a/core/services/relay/evm/read/batch.go +++ b/core/services/relay/evm/read/batch.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/codec" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" ) @@ -134,7 +135,7 @@ func (c *defaultEvmBatchCaller) batchCall(ctx context.Context, blockNumber uint6 packedOutputs := make([]string, len(batchCall)) rpcBatchCalls := make([]rpc.BatchElem, len(batchCall)) for i, call := range batchCall { - data, err := c.codec.Encode(ctx, call.Params, WrapItemType(call.ContractName, call.MethodName, true)) + data, err := c.codec.Encode(ctx, call.Params, codec.WrapItemType(call.ContractName, call.MethodName, true)) if err != nil { return nil, err } @@ -187,7 +188,7 @@ func (c *defaultEvmBatchCaller) batchCall(ctx context.Context, blockNumber uint6 return nil, fmt.Errorf("decode result %s: packedOutputs %s: %w", call, packedOutputs[i], err) } - if err = c.codec.Decode(ctx, b, call.ReturnVal, WrapItemType(call.ContractName, call.MethodName, false)); err != nil { + if err = c.codec.Decode(ctx, b, call.ReturnVal, codec.WrapItemType(call.ContractName, call.MethodName, false)); err != nil { if len(b) == 0 { results[i].err = fmt.Errorf("unpack result %s: %s: %w", call, err.Error(), errEmptyOutput) } else { @@ -314,11 +315,3 @@ func convertToBatchResult(data []dataAndErr) BatchResult { return batchResult } - -func WrapItemType(contractName, itemType string, isParams bool) string { - if isParams { - return fmt.Sprintf("params.%s.%s", contractName, itemType) - } - - return fmt.Sprintf("return.%s.%s", contractName, itemType) -} diff --git a/core/services/relay/evm/read/bindings.go b/core/services/relay/evm/read/bindings.go index 0b6ea311109..55f237af0eb 100644 --- a/core/services/relay/evm/read/bindings.go +++ b/core/services/relay/evm/read/bindings.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "strings" "sync" "github.com/ethereum/go-ethereum/common" @@ -11,6 +12,7 @@ import ( 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/services/relay/evm/codec" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -85,10 +87,24 @@ func (b *BindingsRegistry) GetReader(readName string) (Reader, string, error) { return binding, values.address, nil } -func (b *BindingsRegistry) AddReader(contractName, readName string, rdr Reader) { +func (b *BindingsRegistry) AddReader(contractName, readName string, rdr Reader) error { b.mu.Lock() defer b.mu.Unlock() + switch v := rdr.(type) { + case *EventBinding: + // unwrap codec type naming for event data words and topics to be used by lookup for Querying by Value Comparators + // For e.g. "params.contractName.eventName.IndexedTopic" -> "eventName.IndexedTopic" + // or "params.contractName.eventName.someFieldInData" -> "eventName.someFieldInData" + for name := range v.eventTypes { + split := strings.Split(name, ".") + if len(split) < 3 || split[1] != contractName { + return fmt.Errorf("invalid event type name %s", name) + } + b.contractLookup.addReadNameForContract(contractName, strings.Join(split[2:], ".")) + } + } + b.contractLookup.addReadNameForContract(contractName, readName) cb, cbExists := b.contractBindings[contractName] @@ -98,6 +114,7 @@ func (b *BindingsRegistry) AddReader(contractName, readName string, rdr Reader) } cb.AddReaderNamed(readName, rdr) + return nil } // Bind binds contract addresses to contract bindings and read bindings. @@ -266,7 +283,7 @@ func (b *BindingsRegistry) ReadTypeIdentifier(readName string, forEncoding bool) return "" } - return WrapItemType(values.contract, values.readName, forEncoding) + return codec.WrapItemType(values.contract, values.readName, forEncoding) } // confidenceToConfirmations matches predefined chain agnostic confidence levels to predefined EVM finality. diff --git a/core/services/relay/evm/read/bindings_test.go b/core/services/relay/evm/read/bindings_test.go index a60cc2933e3..d9cfa91a987 100644 --- a/core/services/relay/evm/read/bindings_test.go +++ b/core/services/relay/evm/read/bindings_test.go @@ -42,7 +42,7 @@ func TestBindingsRegistry(t *testing.T) { named := read.NewBindingsRegistry() named.SetBatchCaller(mBatch) - named.AddReader(contractName1, methodName1, mRdr) + require.NoError(t, named.AddReader(contractName1, methodName1, mRdr)) bindings := []commontypes.BoundContract{{Address: "0x24", Name: contractName1}} _ = named.Bind(context.Background(), mReg, bindings) @@ -78,8 +78,8 @@ func TestBindingsRegistry(t *testing.T) { mRdr1.EXPECT().GetLatestValue(mock.Anything, common.HexToAddress("0x26"), mock.Anything, mock.Anything, mock.Anything).Return(nil) // part of the init phase of chain reader - named.AddReader(contractName1, methodName1, mRdr0) - named.AddReader(contractName1, methodName2, mRdr1) + require.NoError(t, named.AddReader(contractName1, methodName1, mRdr0)) + require.NoError(t, named.AddReader(contractName1, methodName2, mRdr1)) _ = named.SetFilter(contractName1, filterWithSigs) // run within the start phase of chain reader diff --git a/core/services/relay/evm/read/event.go b/core/services/relay/evm/read/event.go index 1630265ea90..03bee7472bc 100644 --- a/core/services/relay/evm/read/event.go +++ b/core/services/relay/evm/read/event.go @@ -16,21 +16,24 @@ import ( 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/services/relay/evm/codec" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/codec" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) type EventBinding struct { // read-only properties - contractName string - eventName string - hash common.Hash - inputInfo types.CodecEntry - inputModifier commoncodec.Modifier - codecTopicInfo types.CodecEntry + contractName string + eventName string + hash common.Hash + // eventTypes has all the types for GetLatestValue unHashed indexed topics params and for QueryKey data words or unHashed indexed topics value comparators. + eventTypes map[string]types.CodecEntry + // indexedTopicsTypes has type info about hashed indexed topics. + indexedTopicsTypes types.CodecEntry + // eventModifiers only has a modifier for indexed topic filtering, but data words can also be added if needed. + eventModifiers map[string]commoncodec.Modifier // dependencies // filterRegistrar in EventBinding is to be used as an override for lp filter defined in the contract binding. @@ -40,14 +43,13 @@ type EventBinding struct { lp logpoller.LogPoller // internal properties / state - codec commontypes.RemoteCodec - bound map[common.Address]bool // bound determines if address is set to the contract binding. - mu sync.RWMutex - topics map[string]topicDetail // topics maps a generic topic name (key) to topic data - // eventDataWords maps a generic name to a word index - // key is a predefined generic name for evm log event data word - // for e.g. first evm data word(32bytes) of USDC log event is value so the key can be called value - eventDataWords map[string]uint8 + codec commontypes.RemoteCodec + bound map[common.Address]bool // bound determines if address is set to the contract binding. + mu sync.RWMutex + // topics map a generic topic name (key) to topic data + topics map[string]TopicDetail + // dataWords key is the generic dataWordNamb. + dataWords map[string]DataWordDetail confirmationsMapping map[primitives.ConfidenceLevel]evmtypes.Confirmations } @@ -55,9 +57,7 @@ func NewEventBinding( contract, event string, poller logpoller.LogPoller, hash common.Hash, - inputInfo types.CodecEntry, - inputModifier commoncodec.Modifier, - codecTopicInfo types.CodecEntry, + indexedTopicsTypes types.CodecEntry, confirmations map[primitives.ConfidenceLevel]evmtypes.Confirmations, ) *EventBinding { return &EventBinding{ @@ -65,21 +65,26 @@ func NewEventBinding( eventName: event, lp: poller, hash: hash, - inputInfo: inputInfo, - inputModifier: inputModifier, - codecTopicInfo: codecTopicInfo, + indexedTopicsTypes: indexedTopicsTypes, confirmationsMapping: confirmations, - topics: make(map[string]topicDetail), - eventDataWords: make(map[string]uint8), + topics: make(map[string]TopicDetail), + dataWords: make(map[string]DataWordDetail), bound: make(map[common.Address]bool), } } -type topicDetail struct { +type TopicDetail struct { abi.Argument Index uint64 } +// DataWordDetail contains all the information about a single evm Data word. +// For b.g. first evm data word(32bytes) of USDC log event is uint256 var called valub. +type DataWordDetail struct { + Index uint8 + abi.Argument +} + var _ Reader = &EventBinding{} func (b *EventBinding) SetCodec(codec commontypes.RemoteCodec) { @@ -89,6 +94,43 @@ func (b *EventBinding) SetCodec(codec commontypes.RemoteCodec) { b.codec = codec } +func (b *EventBinding) SetFilter(filter logpoller.Filter) { + b.mu.Lock() + defer b.mu.Unlock() + + b.registrar = newSyncedFilter() + b.registrar.SetFilter(filter) +} + +func (b *EventBinding) SetCodecTypesAndModifiers(types map[string]types.CodecEntry, modifiers map[string]commoncodec.Modifier) { + b.mu.Lock() + defer b.mu.Unlock() + + b.eventTypes = types + b.eventModifiers = modifiers +} + +func (b *EventBinding) SetDataWordsDetails(dwDetail map[string]DataWordDetail) { + b.mu.Lock() + defer b.mu.Unlock() + + b.dataWords = dwDetail +} + +func (b *EventBinding) SetTopicDetails(topicDetails map[string]TopicDetail) { + b.mu.Lock() + defer b.mu.Unlock() + + b.topics = topicDetails +} + +func (b *EventBinding) GetDataWords() map[string]DataWordDetail { + b.mu.RLock() + defer b.mu.RUnlock() + + return b.dataWords +} + func (b *EventBinding) Bind(ctx context.Context, bindings ...common.Address) error { if b.hasBindings() { // we are changing contract address reference, so we need to unregister old filter if it exists @@ -194,25 +236,44 @@ func (b *EventBinding) GetLatestValue(ctx context.Context, address common.Addres return err } - confirmations, err := confidenceToConfirmations(b.confirmationsMapping, confidenceLevel) + confs, err := confidenceToConfirmations(b.confirmationsMapping, confidenceLevel) + if err != nil { + return err + } + + topicTypeID := codec.WrapItemType(b.contractName, b.eventName, true) + + onChainTypedVal, err := b.toNativeOnChainType(topicTypeID, params) + if err != nil { + return fmt.Errorf("failed to convert params to native on chain types: %w", err) + } + + filterTopics, err := b.extractFilterTopics(topicTypeID, onChainTypedVal) if err != nil { return err } - if len(b.inputInfo.Args()) == 0 { - return b.getLatestValueWithoutFilters(ctx, address, confirmations, into) + var log *logpoller.Log + if len(filterTopics) != 0 { + var hashedTopics []common.Hash + hashedTopics, err = b.hashTopics(topicTypeID, filterTopics) + if err != nil { + return err + } + + if log, err = b.getLatestLog(ctx, address, confs, hashedTopics); err != nil { + return err + } + } else { + if log, err = b.lp.LatestLogByEventSigWithConfs(ctx, b.hash, address, confs); err != nil { + return wrapInternalErr(err) + } } - return b.getLatestValueWithFilters(ctx, address, confirmations, params, into) + return b.decodeLog(ctx, log, into) } -func (b *EventBinding) QueryKey( - ctx context.Context, - address common.Address, - filter query.KeyFilter, - limitAndSort query.LimitAndSort, - sequenceDataType any, -) ([]commontypes.Sequence, error) { +func (b *EventBinding) QueryKey(ctx context.Context, address common.Address, filter query.KeyFilter, limitAndSort query.LimitAndSort, sequenceDataType any) ([]commontypes.Sequence, error) { if err := b.validateBound(address); err != nil { return nil, err } @@ -227,10 +288,9 @@ func (b *EventBinding) QueryKey( logpoller.NewAddressFilter(address), logpoller.NewEventSigFilter(b.hash), } - remapped.Expressions = append(defaultExpressions, remapped.Expressions...) - logs, err := b.lp.FilteredLogs(ctx, remapped.Expressions, limitAndSort, b.contractName+"-"+address.String()+""+b.eventName) + logs, err := b.lp.FilteredLogs(ctx, remapped.Expressions, limitAndSort, b.contractName+"-"+address.String()+"-"+b.eventName) if err != nil { return nil, err } @@ -243,208 +303,124 @@ func (b *EventBinding) QueryKey( return b.decodeLogsIntoSequences(ctx, logs, sequenceDataType) } -func (b *EventBinding) SetFilter(filter logpoller.Filter) { - b.mu.Lock() - defer b.mu.Unlock() - - b.registrar = newSyncedFilter() - b.registrar.SetFilter(filter) -} - -func (b *EventBinding) WithTopic(name string, topic abi.Argument, index uint64) { - b.mu.Lock() - defer b.mu.Unlock() - - b.topics[name] = topicDetail{ - Argument: topic, - Index: index, - } -} - -func (b *EventBinding) SetDataWords(eventDataWords map[string]uint8) { - b.mu.Lock() - defer b.mu.Unlock() - - b.eventDataWords = eventDataWords -} - -func (b *EventBinding) GetDataWords() map[string]uint8 { - b.mu.RLock() - defer b.mu.RUnlock() - - return b.eventDataWords -} - -func (b *EventBinding) validateBound(address common.Address) error { - b.mu.Lock() - defer b.mu.Unlock() - - bound, exists := b.bound[address] - if !exists || !bound { - return fmt.Errorf( - "%w: event %s that belongs to contract: %s, not bound", - commontypes.ErrInvalidType, - b.eventName, - b.contractName, - ) - } - - return nil -} - -func (b *EventBinding) getLatestValueWithoutFilters( - ctx context.Context, - address common.Address, - confs evmtypes.Confirmations, - into any, -) error { - log, err := b.lp.LatestLogByEventSigWithConfs(ctx, b.hash, address, confs) - if err = wrapInternalErr(err); err != nil { - return err - } - - return b.decodeLog(ctx, log, into) -} - -func (b *EventBinding) getLatestValueWithFilters( - ctx context.Context, - address common.Address, - confs evmtypes.Confirmations, - params, into any, -) error { - offChain, err := b.convertToOffChainType(params) - if err != nil { - return err - } - - checkedParams, err := b.inputModifier.TransformToOnChain(offChain, "" /* unused */) - if err != nil { - return err - } - - nativeParams, err := b.inputInfo.ToNative(reflect.ValueOf(checkedParams)) - if err != nil { - return err - } - - filtersAndIndices, err := b.encodeParams(nativeParams) +func (b *EventBinding) getLatestLog(ctx context.Context, address common.Address, confs evmtypes.Confirmations, hashedTopics []common.Hash) (*logpoller.Log, error) { + // Create limiter and filter for the query. + limiter := query.NewLimitAndSort(query.CountLimit(1), query.NewSortBySequence(query.Desc)) + topicFilters, err := createTopicFilters(hashedTopics) if err != nil { - return err + return nil, err } - remainingFilters := filtersAndIndices[1:] - - // Create limiter and filter for the query. - limiter := query.NewLimitAndSort(query.CountLimit(1), query.NewSortBySequence(query.Desc)) - filter, err := query.Where( - "", + filter, err := logpoller.Where( + topicFilters, logpoller.NewAddressFilter(address), logpoller.NewEventSigFilter(b.hash), logpoller.NewConfirmationsFilter(confs), - createTopicFilters(filtersAndIndices), ) if err != nil { - return wrapInternalErr(err) + return nil, wrapInternalErr(err) } // Gets the latest log that matches the filter and limiter. - logs, err := b.lp.FilteredLogs(ctx, filter.Expressions, limiter, b.contractName+"-"+address.String()+"-"+b.eventName) + logs, err := b.lp.FilteredLogs(ctx, filter, limiter, b.contractName+"-"+address.String()+"-"+b.eventName) if err != nil { - return wrapInternalErr(err) - } - - // 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 - } + return nil, wrapInternalErr(err) } - if logToUse == nil { - return fmt.Errorf("%w: no events found", commontypes.ErrNotFound) + if len(logs) == 0 { + return nil, fmt.Errorf("%w: no events found", commontypes.ErrNotFound) } - - return b.decodeLog(ctx, logToUse, into) + return &logs[0], err } -func (b *EventBinding) convertToOffChainType(params any) (any, error) { - offChain, err := b.codec.CreateType(WrapItemType(b.contractName, b.eventName, true), true) - if err != nil { - return nil, err - } +func (b *EventBinding) decodeLogsIntoSequences(ctx context.Context, logs []logpoller.Log, into any) ([]commontypes.Sequence, error) { + sequences := make([]commontypes.Sequence, len(logs)) - if err = codec.MapstructureDecode(params, offChain); err != nil { - return nil, err - } + for idx := range logs { + sequences[idx] = commontypes.Sequence{ + Cursor: fmt.Sprintf("%s-%s-%d", logs[idx].BlockHash, logs[idx].TxHash, logs[idx].LogIndex), + Head: commontypes.Head{ + Height: fmt.Sprint(logs[idx].BlockNumber), + Hash: logs[idx].BlockHash.Bytes(), + Timestamp: uint64(logs[idx].BlockTimestamp.Unix()), + }, + } - return offChain, nil -} + var typeVal reflect.Value + + typeInto := reflect.TypeOf(into) + if typeInto.Kind() == reflect.Pointer { + typeVal = reflect.New(typeInto.Elem()) + } else { + typeVal = reflect.Indirect(reflect.New(typeInto)) + } + + // create a new value of the same type as 'into' for the data to be extracted to + sequences[idx].Data = typeVal.Interface() -func (b *EventBinding) encodeParams(item reflect.Value) ([]common.Hash, error) { - for item.Kind() == reflect.Pointer { - item = reflect.Indirect(item) + if err := b.decodeLog(ctx, &logs[idx], sequences[idx].Data); err != nil { + return nil, err + } } + return sequences, nil +} - var params []any +// extractFilterTopics extracts filter topics from input params and returns them as a slice of any. +// returned slice will retain the order of the topics and fill in missing topics with nil, if all values are nil, empty slice is returned. +func (b *EventBinding) extractFilterTopics(topicTypeID string, value any) (filterTopics []any, err error) { + item := reflect.ValueOf(value) switch item.Kind() { case reflect.Array, reflect.Slice: - native, err := codec.RepresentArray(item, b.inputInfo) + var native any + native, err = codec.RepresentArray(item, b.eventTypes[topicTypeID]) if err != nil { return nil, err } - params = []any{native} + filterTopics = []any{native} case reflect.Struct, reflect.Map: - var err error - if params, err = codec.UnrollItem(item, b.inputInfo); err != nil { + if filterTopics, err = codec.UnrollItem(item, b.eventTypes[topicTypeID]); err != nil { return nil, err } default: return nil, fmt.Errorf("%w: cannot encode kind %v", commontypes.ErrInvalidType, item.Kind()) } - // abi params allow you to Pack a pointers, but MakeTopics doesn't work with pointers. - if err := b.derefTopics(params); err != nil { - return nil, err + // check if at least one topic filter is present + for _, filterVal := range derefValues(filterTopics) { + if filterVal != nil { + return filterTopics, nil + } } - return b.makeTopics(params) + return []any{}, nil } -func (b *EventBinding) derefTopics(topics []any) error { - for i, topic := range topics { - rTopic := reflect.ValueOf(topic) - if rTopic.Kind() == reflect.Pointer { - if rTopic.IsNil() { - return fmt.Errorf( - "%w: input topic %s cannot be nil", commontypes.ErrInvalidType, b.inputInfo.Args()[i].Name) - } - - topics[i] = rTopic.Elem().Interface() +// hashTopics hashes topic filters values to match on chain indexed topics. +func (b *EventBinding) hashTopics(topicTypeID string, topics []any) ([]common.Hash, error) { + var hashableTopics []any + for i, topic := range derefValues(topics) { + if topic == nil { + continue } - } - return nil -} + // make topic value for non-fixed bytes array manually because geth MakeTopics doesn't support it + topicTyp, exists := b.eventTypes[topicTypeID] + if !exists { + return nil, fmt.Errorf("cannot find event type entry") + } -// makeTopics encodes and hashes params filtering values to match onchain indexed topics. -func (b *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 := b.inputInfo.Args()[i]; abiArg.Type.T == abi.ArrayTy && (abiArg.Type.Elem != nil && abiArg.Type.Elem.T == abi.UintTy) { + if abiArg := topicTyp.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) + topic = crypto.Keccak256Hash(packed) } + + hashableTopics = append(hashableTopics, topic) } - hashes, err := abi.MakeTopics(params) + hashes, err := abi.MakeTopics(hashableTopics) if err != nil { return nil, wrapInternalErr(err) } @@ -457,11 +433,13 @@ func (b *EventBinding) makeTopics(params []any) ([]common.Hash, error) { } func (b *EventBinding) decodeLog(ctx context.Context, log *logpoller.Log, into any) error { - if err := b.codec.Decode(ctx, log.Data, into, WrapItemType(b.contractName, b.eventName, false)); err != nil { + // decode non indexed topics and apply output modifiers + if err := b.codec.Decode(ctx, log.Data, into, codec.WrapItemType(b.contractName, b.eventName, false)); err != nil { return err } - topics := make([]common.Hash, len(b.codecTopicInfo.Args())) + // 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(b.indexedTopicsTypes.Args())) if len(log.Topics) < len(topics)+1 { return fmt.Errorf("%w: not enough topics to decode", commontypes.ErrInvalidType) } @@ -471,49 +449,15 @@ func (b *EventBinding) decodeLog(ctx context.Context, log *logpoller.Log, into a } topicsInto := map[string]any{} - if err := abi.ParseTopicsIntoMap(topicsInto, b.codecTopicInfo.Args(), topics); err != nil { + if err := abi.ParseTopicsIntoMap(topicsInto, b.indexedTopicsTypes.Args(), topics); err != nil { return fmt.Errorf("%w: %w", commontypes.ErrInvalidType, err) } return codec.MapstructureDecode(topicsInto, into) } -func (b *EventBinding) decodeLogsIntoSequences(ctx context.Context, logs []logpoller.Log, into any) ([]commontypes.Sequence, error) { - sequences := make([]commontypes.Sequence, len(logs)) - - for idx := range logs { - sequences[idx] = commontypes.Sequence{ - Cursor: fmt.Sprintf("%s-%s-%d", logs[idx].BlockHash, logs[idx].TxHash, logs[idx].LogIndex), - Head: commontypes.Head{ - Height: fmt.Sprint(logs[idx].BlockNumber), - Hash: logs[idx].BlockHash.Bytes(), - Timestamp: uint64(logs[idx].BlockTimestamp.Unix()), - }, - } - - var typeVal reflect.Value - - typeInto := reflect.TypeOf(into) - if typeInto.Kind() == reflect.Pointer { - typeVal = reflect.New(typeInto.Elem()) - } else { - typeVal = reflect.Indirect(reflect.New(typeInto)) - } - - // create a new value of the same type as 'into' for the data to be extracted to - sequences[idx].Data = typeVal.Interface() - - if err := b.decodeLog(ctx, &logs[idx], sequences[idx].Data); err != nil { - return nil, err - } - } - - return sequences, nil -} - -func (b *EventBinding) remap(filter query.KeyFilter) (query.KeyFilter, error) { - remapped := query.KeyFilter{} - +// remap chain agnostic primitives to chain specific logPoller primitives. +func (b *EventBinding) remap(filter query.KeyFilter) (remapped query.KeyFilter, err error) { for _, expression := range filter.Expressions { remappedExpression, err := b.remapExpression(filter.Key, expression) if err != nil { @@ -529,7 +473,6 @@ func (b *EventBinding) remap(filter query.KeyFilter) (query.KeyFilter, error) { func (b *EventBinding) remapExpression(key string, expression query.Expression) (query.Expression, error) { if !expression.IsPrimitive() { remappedBoolExpressions := make([]query.Expression, len(expression.BoolExpression.Expressions)) - for i := range expression.BoolExpression.Expressions { remapped, err := b.remapExpression(key, expression.BoolExpression.Expressions[i]) if err != nil { @@ -546,18 +489,17 @@ func (b *EventBinding) remapExpression(key string, expression query.Expression) return query.Or(remappedBoolExpressions...), nil } - return b.remapPrimitive(key, expression) + return b.remapPrimitive(expression) } -// remap chain agnostic primitives to chain specific -func (b *EventBinding) remapPrimitive(key string, expression query.Expression) (query.Expression, error) { +func (b *EventBinding) remapPrimitive(expression query.Expression) (query.Expression, error) { switch primitive := expression.Primitive.(type) { case *primitives.Comparator: - if val, ok := b.eventDataWords[primitive.Name]; ok { - return logpoller.NewEventByWordFilter(b.hash, val, primitive.ValueComparators), nil + hashedValComps, err := b.encodeComparator(primitive) + if err != nil { + return query.Expression{}, fmt.Errorf("failed to encode comparator %q: %w", primitive.Name, err) } - - return logpoller.NewEventByTopicFilter(b.topics[key].Index, primitive.ValueComparators), nil + return hashedValComps, nil case *primitives.Confidence: confirmations, err := confidenceToConfirmations(b.confirmationsMapping, primitive.ConfidenceLevel) if err != nil { @@ -570,63 +512,148 @@ func (b *EventBinding) remapPrimitive(key string, expression query.Expression) ( } } -func (b *EventBinding) hasBindings() bool { - b.mu.RLock() - defer b.mu.RUnlock() +func (b *EventBinding) encodeComparator(comparator *primitives.Comparator) (query.Expression, error) { + dwInfo, isDW := b.dataWords[comparator.Name] + if !isDW { + if _, exists := b.topics[comparator.Name]; !exists { + return query.Expression{}, fmt.Errorf("comparator name doesn't match any of the indexed topics or data words") + } + } - return len(b.bound) > 0 + var hashedValComps []logpoller.HashedValueComparator + itemType := codec.WrapItemType(b.contractName, b.eventName+"."+comparator.Name, true) + for _, valComp := range comparator.ValueComparators { + onChainTypedVal, err := b.toNativeOnChainType(itemType, valComp.Value) + if err != nil { + return query.Expression{}, fmt.Errorf("failed to convert comparator value to native on chain type: %w", err) + } + + hashedValComp := logpoller.HashedValueComparator{Operator: valComp.Operator} + if isDW { + hashedValComp.Value, err = b.encodeValComparatorDataWord(itemType, onChainTypedVal) + } else { + hashedValComp.Value, err = b.encodeValComparatorTopic(itemType, onChainTypedVal) + } + if err != nil { + return query.Expression{}, err + } + hashedValComps = append(hashedValComps, hashedValComp) + } + + if isDW { + return logpoller.NewEventByWordFilter(dwInfo.Index, hashedValComps), nil + } + + return logpoller.NewEventByTopicFilter(b.topics[comparator.Name].Index, hashedValComps), nil } -func (b *EventBinding) isBound(binding common.Address) bool { - b.mu.RLock() - defer b.mu.RUnlock() +func (b *EventBinding) encodeValComparatorDataWord(dwTypeID string, value any) (hash common.Hash, err error) { + dwTypes, exists := b.eventTypes[dwTypeID] + if !exists { + return common.Hash{}, fmt.Errorf("cannot find data word type for %s", dwTypeID) + } - _, exists := b.bound[binding] + packedArgs, err := dwTypes.Args().Pack(value) + if err != nil { + return common.Hash{}, err + } - return exists + return common.BytesToHash(packedArgs), nil } -func (b *EventBinding) addBinding(binding common.Address) { - b.mu.Lock() - defer b.mu.Unlock() +func (b *EventBinding) encodeValComparatorTopic(topicTypeID string, value any) (hash common.Hash, err error) { + hashedTopics, err := b.hashTopics(topicTypeID, []any{value}) + if err != nil { + return common.Hash{}, err + } - b.bound[binding] = true + return hashedTopics[0], nil } -func (b *EventBinding) removeBinding(binding common.Address) { - b.mu.Lock() - defer b.mu.Unlock() +// toNativeOnChainType converts value into its on chain version by applying codec modifiers, map structure hooks and abi typing. +func (b *EventBinding) toNativeOnChainType(itemType string, value any) (any, error) { + offChain, err := b.codec.CreateType(itemType, true) + if err != nil { + return nil, fmt.Errorf("failed to create type: %w", err) + } - delete(b.bound, binding) + // apply map struct evm hooks to correct incoming values + if err = codec.MapstructureDecode(value, offChain); err != nil { + return nil, err + } + + // apply modifiers if present + onChain := offChain + if modifier, exists := b.eventModifiers[itemType]; exists { + onChain, err = modifier.TransformToOnChain(offChain, "" /* unused */) + if err != nil { + return nil, fmt.Errorf("failed to apply modifiers to offchain type %T: %w", onChain, err) + } + } + + typ, exists := b.eventTypes[itemType] + if !exists { + return query.Expression{}, fmt.Errorf("cannot find event type entry") + } + + native, err := typ.ToNative(reflect.ValueOf(onChain)) + if err != nil { + return query.Expression{}, err + } + + for native.Kind() == reflect.Pointer { + native = reflect.Indirect(native) + } + + return native.Interface(), nil } -func (b *EventBinding) registered() bool { - b.mu.RLock() - defer b.mu.RUnlock() +func (b *EventBinding) validateBound(address common.Address) error { + b.mu.Lock() + defer b.mu.Unlock() - return b.registerCalled + bound, exists := b.bound[address] + if !exists || !bound { + return fmt.Errorf( + "%w: event %s that belongs to contract: %s, not bound", + commontypes.ErrInvalidType, + b.eventName, + b.contractName, + ) + } + + return nil } -func compareLogs(log, use *logpoller.Log) int64 { - if use == nil { - return 1 +func createTopicFilters(hashedTopics []common.Hash) (query.Expression, error) { + var expressions []query.Expression + for topicID, hash := range hashedTopics { + // first topic index is 1-based, so we add 1. + expressions = append(expressions, logpoller.NewEventByTopicFilter( + uint64(topicID+1), []logpoller.HashedValueComparator{{Value: hash, Operator: primitives.Eq}}, + )) } - if log.BlockNumber != use.BlockNumber { - return log.BlockNumber - use.BlockNumber + if len(expressions) == 0 { + return query.Expression{}, fmt.Errorf("%w: no topic filters found during query creation", commontypes.ErrInternal) } - return log.LogIndex - use.LogIndex + return query.And(expressions...), nil } -func matchesRemainingFilters(log *logpoller.Log, filters []common.Hash) bool { - for i, rfai := range filters { - if !reflect.DeepEqual(rfai[:], log.Topics[i+2]) { - return false +// derefValues dereferences pointers to nil values to nil. +func derefValues(topics []any) []any { + for i, topic := range topics { + rTopic := reflect.ValueOf(topic) + if rTopic.Kind() == reflect.Pointer { + if rTopic.IsNil() { + topics[i] = nil + } else { + topics[i] = rTopic.Elem().Interface() + } } } - - return true + return topics } func wrapInternalErr(err error) error { @@ -638,17 +665,42 @@ func wrapInternalErr(err error) error { if strings.Contains(errStr, "not found") || strings.Contains(errStr, "no rows") { return fmt.Errorf("%w: %w", commontypes.ErrNotFound, err) } - return fmt.Errorf("%w: %w", commontypes.ErrInternal, err) } -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...) +func (b *EventBinding) hasBindings() bool { + b.mu.RLock() + defer b.mu.RUnlock() + + return len(b.bound) > 0 +} + +func (b *EventBinding) isBound(binding common.Address) bool { + b.mu.RLock() + defer b.mu.RUnlock() + + _, exists := b.bound[binding] + + return exists +} + +func (b *EventBinding) addBinding(binding common.Address) { + b.mu.Lock() + defer b.mu.Unlock() + + b.bound[binding] = true +} + +func (b *EventBinding) removeBinding(binding common.Address) { + b.mu.Lock() + defer b.mu.Unlock() + + delete(b.bound, binding) +} + +func (b *EventBinding) registered() bool { + b.mu.RLock() + defer b.mu.RUnlock() + + return b.registerCalled } diff --git a/core/services/relay/evm/read/method.go b/core/services/relay/evm/read/method.go index 3f29b00ce95..26a72544716 100644 --- a/core/services/relay/evm/read/method.go +++ b/core/services/relay/evm/read/method.go @@ -13,6 +13,7 @@ import ( 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/services/relay/evm/codec" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -124,7 +125,7 @@ func (b *MethodBinding) GetLatestValue(ctx context.Context, addr common.Address, return fmt.Errorf("%w: method not bound", commontypes.ErrInvalidType) } - data, err := b.codec.Encode(ctx, params, WrapItemType(b.contractName, b.method, true)) + data, err := b.codec.Encode(ctx, params, codec.WrapItemType(b.contractName, b.method, true)) if err != nil { return err } @@ -145,7 +146,7 @@ func (b *MethodBinding) GetLatestValue(ctx context.Context, addr common.Address, return fmt.Errorf("%w: %w", commontypes.ErrInternal, err) } - return b.codec.Decode(ctx, bytes, returnVal, WrapItemType(b.contractName, b.method, false)) + return b.codec.Decode(ctx, bytes, returnVal, codec.WrapItemType(b.contractName, b.method, false)) } func (b *MethodBinding) QueryKey( diff --git a/core/services/relay/evm/types/codec_entry.go b/core/services/relay/evm/types/codec_entry.go index 9a8103cf7f9..4e18f4d9f9f 100644 --- a/core/services/relay/evm/types/codec_entry.go +++ b/core/services/relay/evm/types/codec_entry.go @@ -57,9 +57,15 @@ func (entry *codecEntry) NativeType() reflect.Type { return entry.nativeType } -func (entry *codecEntry) ToNative(checked reflect.Value) (reflect.Value, error) { +func (entry *codecEntry) ToNative(checked reflect.Value) (val reflect.Value, err error) { + defer func() { + if r := recover(); r != nil { + val = reflect.Value{} + err = fmt.Errorf("invalid checked value: %v", r) + } + }() if checked.Type() != reflect.PointerTo(entry.checkedType) { - return reflect.Value{}, fmt.Errorf("%w: checked type %v does not match expected type %v", commontypes.ErrInvalidType, reflect.TypeOf(checked), entry.checkedType) + return reflect.Value{}, fmt.Errorf("%w: checked type %v does not match expected type %v", commontypes.ErrInvalidType, checked.Type(), entry.checkedType) } return reflect.NewAt(entry.nativeType, checked.UnsafePointer()), nil diff --git a/core/services/relay/evm/types/types.go b/core/services/relay/evm/types/types.go index ac9690e2a6b..c1f814c5965 100644 --- a/core/services/relay/evm/types/types.go +++ b/core/services/relay/evm/types/types.go @@ -100,11 +100,9 @@ type EventDefinitions struct { // GenericTopicNames helps QueryingKeys not rely on EVM specific topic names. Key is chain specific name, value is generic name. // This helps us translate chain agnostic querying key "transfer-value" to EVM specific "evmTransferEvent-weiAmountTopic". GenericTopicNames map[string]string `json:"genericTopicNames,omitempty"` - // key is a predefined generic name for evm log event data word - // for e.g. first evm data word(32bytes) of USDC log event is value so the key can be called value - GenericDataWordNames map[string]uint8 `json:"genericDataWordNames,omitempty"` - // InputFields allows you to choose which indexed fields are expected from the input - InputFields []string `json:"inputFields,omitempty"` + // GenericDataWordNames key is generic name for evm log event data word that maps to on chain name. + // For e.g. first evm data word(32bytes) of USDC log event is value so the key can be called value. + GenericDataWordNames map[string]string `json:"genericDataWordDefs,omitempty"` // PollingFilter should be defined on a contract level in ContractPollingFilter, // unless event needs to override the contract level filter options. // This will create a separate log poller filter for this event. diff --git a/core/services/relay/evm/types/types_test.go b/core/services/relay/evm/types/types_test.go index 37d5e77693a..11825ae5c40 100644 --- a/core/services/relay/evm/types/types_test.go +++ b/core/services/relay/evm/types/types_test.go @@ -80,7 +80,7 @@ func Test_ChainReaderConfig(t *testing.T) { } }, "configs":{ - "config1":"{\"cacheEnabled\":true,\"chainSpecificName\":\"specificName1\",\"inputModifications\":[{\"Fields\":[\"ts\"],\"Type\":\"epoch to time\"},{\"Fields\":{\"a\":\"b\"},\"Type\":\"rename\"}],\"outputModifications\":[{\"Fields\":[\"ts\"],\"Type\":\"epoch to time\"},{\"Fields\":{\"c\":\"d\"},\"Type\":\"rename\"}],\"eventDefinitions\":{\"genericTopicNames\":{\"TopicKey1\":\"TopicVal1\"},\"genericDataWordNames\":{\"DataWordKey\":1},\"inputFields\":[\"Event1\",\"Event2\"],\"pollingFilter\":{\"topic2\":[\"0x4abbe4784b1fb071039bb9cb50b82978fb5d3ab98fb512c032e75786b93e2c52\"],\"topic3\":[\"0x5abbe4784b1fb071039bb9cb50b82978fb5d3ab98fb512c032e75786b93e2c52\"],\"topic4\":[\"0x6abbe4784b1fb071039bb9cb50b82978fb5d3ab98fb512c032e75786b93e2c52\"],\"retention\":\"1m0s\",\"maxLogsKept\":100,\"logsPerBlock\":10}},\"confidenceConfirmations\":{\"0.0\":0,\"1.0\":-1}}" + "config1":"{\"cacheEnabled\":true,\"chainSpecificName\":\"specificName1\",\"inputModifications\":[{\"Fields\":[\"ts\"],\"Type\":\"epoch to time\"},{\"Fields\":{\"a\":\"b\"},\"Type\":\"rename\"}],\"outputModifications\":[{\"Fields\":[\"ts\"],\"Type\":\"epoch to time\"},{\"Fields\":{\"c\":\"d\"},\"Type\":\"rename\"}],\"eventDefinitions\":{\"genericTopicNames\":{\"TopicKey1\":\"TopicVal1\"},\"genericDataWordDefs\":{\"DataWordKey\": \"DataWordKey\"},\"pollingFilter\":{\"topic2\":[\"0x4abbe4784b1fb071039bb9cb50b82978fb5d3ab98fb512c032e75786b93e2c52\"],\"topic3\":[\"0x5abbe4784b1fb071039bb9cb50b82978fb5d3ab98fb512c032e75786b93e2c52\"],\"topic4\":[\"0x6abbe4784b1fb071039bb9cb50b82978fb5d3ab98fb512c032e75786b93e2c52\"],\"retention\":\"1m0s\",\"maxLogsKept\":100,\"logsPerBlock\":10}},\"confidenceConfirmations\":{\"0.0\":0,\"1.0\":-1}}" } } } @@ -128,8 +128,7 @@ func Test_ChainReaderConfig(t *testing.T) { ConfidenceConfirmations: map[string]int{"0.0": 0, "1.0": -1}, EventDefinitions: &EventDefinitions{ GenericTopicNames: map[string]string{"TopicKey1": "TopicVal1"}, - GenericDataWordNames: map[string]uint8{"DataWordKey": 1}, - InputFields: []string{"Event1", "Event2"}, + GenericDataWordNames: map[string]string{"DataWordKey": "DataWordKey"}, PollingFilter: &PollingFilter{ Topic2: evmtypes.HashArray{common.HexToHash("0x4abbe4784b1fb071039bb9cb50b82978fb5d3ab98fb512c032e75786b93e2c52")}, Topic3: evmtypes.HashArray{common.HexToHash("0x5abbe4784b1fb071039bb9cb50b82978fb5d3ab98fb512c032e75786b93e2c52")}, diff --git a/go.mod b/go.mod index f5b4216e29a..36160f8e96e 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/dominikbraun/graph v0.23.0 github.com/esote/minmaxheap v1.0.0 github.com/ethereum/go-ethereum v1.13.8 - github.com/fatih/color v1.16.0 + github.com/fatih/color v1.17.0 github.com/fxamacker/cbor/v2 v2.7.0 github.com/gagliardetto/solana-go v1.8.4 github.com/getsentry/sentry-go v0.23.0 @@ -75,7 +75,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.23 github.com/smartcontractkit/chainlink-automation v1.0.4 github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612 - github.com/smartcontractkit/chainlink-common v0.2.2-0.20240916150342-36cb47701edf + github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 github.com/smartcontractkit/chainlink-feeds v0.0.0-20240910155501-42f20443189f @@ -104,14 +104,14 @@ require ( go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.27.0 - golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa - golang.org/x/mod v0.20.0 + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 + golang.org/x/mod v0.21.0 golang.org/x/net v0.29.0 golang.org/x/sync v0.8.0 golang.org/x/term v0.24.0 golang.org/x/text v0.18.0 golang.org/x/time v0.6.0 - golang.org/x/tools v0.24.0 + golang.org/x/tools v0.25.0 gonum.org/v1/gonum v0.15.0 google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 diff --git a/go.sum b/go.sum index 4c05468ad67..85fdab94061 100644 --- a/go.sum +++ b/go.sum @@ -335,8 +335,8 @@ github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+ne github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= @@ -1044,8 +1044,8 @@ github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8um github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612 h1:xPEM9XbfZmv8N3NjZ7AX5salonll/LdXrbb8JCbA4FE= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612/go.mod h1:Lv77O13ZxOdmlvnu2vaUC0Lg+t3JAL+N+9K8dRsgmDI= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240916150342-36cb47701edf h1:1AlTUkT5D8HmvU9bwDoIN54/EFyOnRBl7gnXZVrYXEA= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240916150342-36cb47701edf/go.mod h1:l8NTByXUdGGJX+vyKYI6yX1/HIpM14F8Wm9BkU3Q4Qo= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 h1:wqLXuPdiUkn7es/epKmOpB0Q0tKdA9FkYPNQZrZ+VJU= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06/go.mod h1:zm+l8gN4LQS1+YvwQDhRz/njirVeWGNiDJKIhCGwaoQ= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7/go.mod h1:BMYE1vC/pGmdFSsOJdPrAA0/4gZ0Xo0SxTMdGspBtRo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 h1:yRk4ektpx/UxwarqAfgxUXLrsYXlaNeP1NOwzHGrK2Q= @@ -1334,8 +1334,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-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= -golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= 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= @@ -1360,8 +1360,8 @@ golang.org/x/mod v0.3.0/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.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -1572,8 +1572,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 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.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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/integration-tests/go.mod b/integration-tests/go.mod index 714c415086c..f8317db1bd1 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -39,7 +39,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.23 github.com/smartcontractkit/chainlink-automation v1.0.4 github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612 - github.com/smartcontractkit/chainlink-common v0.2.2-0.20240916150342-36cb47701edf + github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.0 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.5 github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0 @@ -57,7 +57,7 @@ require ( go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.27.0 - golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/sync v0.8.0 golang.org/x/text v0.18.0 google.golang.org/grpc v1.65.0 @@ -199,7 +199,7 @@ require ( 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/fatih/color v1.17.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect @@ -481,13 +481,13 @@ require ( 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/mod v0.20.0 // indirect + golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/term v0.24.0 // indirect golang.org/x/time v0.6.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/tools v0.25.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 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 2494576bc4d..f5ad0d35cc0 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -512,8 +512,8 @@ github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwo github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= @@ -1425,8 +1425,8 @@ github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8um github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612 h1:xPEM9XbfZmv8N3NjZ7AX5salonll/LdXrbb8JCbA4FE= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612/go.mod h1:Lv77O13ZxOdmlvnu2vaUC0Lg+t3JAL+N+9K8dRsgmDI= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240916150342-36cb47701edf h1:1AlTUkT5D8HmvU9bwDoIN54/EFyOnRBl7gnXZVrYXEA= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240916150342-36cb47701edf/go.mod h1:l8NTByXUdGGJX+vyKYI6yX1/HIpM14F8Wm9BkU3Q4Qo= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 h1:wqLXuPdiUkn7es/epKmOpB0Q0tKdA9FkYPNQZrZ+VJU= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06/go.mod h1:zm+l8gN4LQS1+YvwQDhRz/njirVeWGNiDJKIhCGwaoQ= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7/go.mod h1:BMYE1vC/pGmdFSsOJdPrAA0/4gZ0Xo0SxTMdGspBtRo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 h1:yRk4ektpx/UxwarqAfgxUXLrsYXlaNeP1NOwzHGrK2Q= @@ -1764,8 +1764,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-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= -golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= 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= @@ -1790,8 +1790,8 @@ golang.org/x/mod v0.3.0/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.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -2058,8 +2058,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 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.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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/integration-tests/load/go.mod b/integration-tests/load/go.mod index 673191e145b..8ebb5638303 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -15,7 +15,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.33.0 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-common v0.2.2-0.20240916150342-36cb47701edf + github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.5 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.1 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.0 @@ -166,7 +166,7 @@ require ( 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/fatih/color v1.17.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fvbommel/sortorder v1.1.0 // indirect @@ -472,8 +472,8 @@ require ( go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.27.0 // indirect - golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect - golang.org/x/mod v0.20.0 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect + golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect golang.org/x/sync v0.8.0 // indirect @@ -481,7 +481,7 @@ require ( golang.org/x/term v0.24.0 // indirect golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.6.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/tools v0.25.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 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index ee64962cb1c..b3a8d086723 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -494,8 +494,8 @@ github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwo github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= @@ -1399,8 +1399,8 @@ github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8um github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612 h1:xPEM9XbfZmv8N3NjZ7AX5salonll/LdXrbb8JCbA4FE= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612/go.mod h1:Lv77O13ZxOdmlvnu2vaUC0Lg+t3JAL+N+9K8dRsgmDI= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240916150342-36cb47701edf h1:1AlTUkT5D8HmvU9bwDoIN54/EFyOnRBl7gnXZVrYXEA= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240916150342-36cb47701edf/go.mod h1:l8NTByXUdGGJX+vyKYI6yX1/HIpM14F8Wm9BkU3Q4Qo= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 h1:wqLXuPdiUkn7es/epKmOpB0Q0tKdA9FkYPNQZrZ+VJU= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06/go.mod h1:zm+l8gN4LQS1+YvwQDhRz/njirVeWGNiDJKIhCGwaoQ= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7/go.mod h1:BMYE1vC/pGmdFSsOJdPrAA0/4gZ0Xo0SxTMdGspBtRo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 h1:yRk4ektpx/UxwarqAfgxUXLrsYXlaNeP1NOwzHGrK2Q= @@ -1738,8 +1738,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-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= -golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= 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= @@ -1764,8 +1764,8 @@ golang.org/x/mod v0.3.0/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.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -2030,8 +2030,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 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.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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= From 1a9f26932d8132c0326016d954a852faca626a05 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 18 Sep 2024 16:36:59 -0500 Subject: [PATCH 02/20] fix lint issues (#14450) --- core/chains/evm/client/config_builder.go | 2 +- core/chains/evm/config/chaintype/chaintype.go | 24 +++++++++---------- core/chains/evm/config/toml/config.go | 4 ++-- core/scripts/vrfv2plus/testnet/main.go | 4 ++-- core/scripts/vrfv2plus/testnet/proofs.go | 2 +- core/services/chainlink/config_test.go | 2 +- .../relay/evm/mercury/wsrpc/mocks/mocks.go | 1 + core/services/vrf/extraargs/types.go | 4 ++-- .../vrf/v2/coordinator_v2x_interface.go | 6 ++--- .../vrf/v2/integration_v2_plus_test.go | 2 +- tools/txtar/visitor.go | 10 ++++---- 11 files changed, 31 insertions(+), 30 deletions(-) diff --git a/core/chains/evm/client/config_builder.go b/core/chains/evm/client/config_builder.go index fa702bac111..e713ec9be24 100644 --- a/core/chains/evm/client/config_builder.go +++ b/core/chains/evm/client/config_builder.go @@ -64,7 +64,7 @@ func NewClientConfigs( chainConfig := &evmconfig.EVMConfig{ C: &toml.EVMConfig{ Chain: toml.Chain{ - ChainType: chaintype.NewChainTypeConfig(chainType), + ChainType: chaintype.NewConfig(chainType), FinalityDepth: finalityDepth, FinalityTagEnabled: finalityTagEnabled, NoNewHeadsThreshold: commonconfig.MustNewDuration(noNewHeadsThreshold), diff --git a/core/chains/evm/config/chaintype/chaintype.go b/core/chains/evm/config/chaintype/chaintype.go index 35dd214b1f5..f6b84e46555 100644 --- a/core/chains/evm/config/chaintype/chaintype.go +++ b/core/chains/evm/config/chaintype/chaintype.go @@ -44,7 +44,7 @@ func (c ChainType) IsValid() bool { return false } -func ChainTypeFromSlug(slug string) ChainType { +func FromSlug(slug string) ChainType { switch slug { case "arbitrum": return ChainArbitrum @@ -79,53 +79,53 @@ func ChainTypeFromSlug(slug string) ChainType { } } -type ChainTypeConfig struct { +type Config struct { value ChainType slug string } -func NewChainTypeConfig(slug string) *ChainTypeConfig { - return &ChainTypeConfig{ - value: ChainTypeFromSlug(slug), +func NewConfig(slug string) *Config { + return &Config{ + value: FromSlug(slug), slug: slug, } } -func (c *ChainTypeConfig) MarshalText() ([]byte, error) { +func (c *Config) MarshalText() ([]byte, error) { if c == nil { return nil, nil } return []byte(c.slug), nil } -func (c *ChainTypeConfig) UnmarshalText(b []byte) error { +func (c *Config) UnmarshalText(b []byte) error { c.slug = string(b) - c.value = ChainTypeFromSlug(c.slug) + c.value = FromSlug(c.slug) return nil } -func (c *ChainTypeConfig) Slug() string { +func (c *Config) Slug() string { if c == nil { return "" } return c.slug } -func (c *ChainTypeConfig) ChainType() ChainType { +func (c *Config) ChainType() ChainType { if c == nil { return "" } return c.value } -func (c *ChainTypeConfig) String() string { +func (c *Config) String() string { if c == nil { return "" } return string(c.value) } -var ErrInvalidChainType = fmt.Errorf("must be one of %s or omitted", strings.Join([]string{ +var ErrInvalid = fmt.Errorf("must be one of %s or omitted", strings.Join([]string{ string(ChainArbitrum), string(ChainAstar), string(ChainCelo), diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index ecc278a7ec5..9fb418cc8df 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -341,7 +341,7 @@ type Chain struct { AutoCreateKey *bool BlockBackfillDepth *uint32 BlockBackfillSkip *bool - ChainType *chaintype.ChainTypeConfig + ChainType *chaintype.Config FinalityDepth *uint32 FinalityTagEnabled *bool FlagsContractAddress *types.EIP55Address @@ -376,7 +376,7 @@ type Chain struct { func (c *Chain) ValidateConfig() (err error) { if !c.ChainType.ChainType().IsValid() { err = multierr.Append(err, commonconfig.ErrInvalid{Name: "ChainType", Value: c.ChainType.ChainType(), - Msg: chaintype.ErrInvalidChainType.Error()}) + Msg: chaintype.ErrInvalid.Error()}) } if c.GasEstimator.BumpTxDepth != nil && *c.GasEstimator.BumpTxDepth > *c.Transactions.MaxInFlight { diff --git a/core/scripts/vrfv2plus/testnet/main.go b/core/scripts/vrfv2plus/testnet/main.go index a37a5391021..f5220f62dd2 100644 --- a/core/scripts/vrfv2plus/testnet/main.go +++ b/core/scripts/vrfv2plus/testnet/main.go @@ -213,7 +213,7 @@ func main() { for i := range preSeedSlice { ps, err := proof.BigToSeed(preSeedSlice[i]) helpers.PanicErr(err) - extraArgs, err := extraargs.ExtraArgsV1(*nativePayment) + extraArgs, err := extraargs.EncodeV1(*nativePayment) helpers.PanicErr(err) preSeedData := proof.PreSeedDataV2Plus{ PreSeed: ps, @@ -308,7 +308,7 @@ func main() { helpers.PanicErr(err) parsedSubID := parseUInt256String(*subID) - extraArgs, err := extraargs.ExtraArgsV1(*nativePayment) + extraArgs, err := extraargs.EncodeV1(*nativePayment) helpers.PanicErr(err) preSeedData := proof.PreSeedDataV2Plus{ PreSeed: ps, diff --git a/core/scripts/vrfv2plus/testnet/proofs.go b/core/scripts/vrfv2plus/testnet/proofs.go index ea6943c63fc..8f1cef0ca6c 100644 --- a/core/scripts/vrfv2plus/testnet/proofs.go +++ b/core/scripts/vrfv2plus/testnet/proofs.go @@ -105,7 +105,7 @@ func generateProofForV2Plus(e helpers.Environment) { if !ok { helpers.PanicErr(fmt.Errorf("unable to parse subID: %s %w", *subId, err)) } - extraArgs, err := extraargs.ExtraArgsV1(*nativePayment) + extraArgs, err := extraargs.EncodeV1(*nativePayment) helpers.PanicErr(err) preSeedData := proof.PreSeedDataV2Plus{ PreSeed: preSeed, diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 8e157de9049..44dc9f98ab0 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -532,7 +532,7 @@ func TestConfig_Marshal(t *testing.T) { }, BlockBackfillDepth: ptr[uint32](100), BlockBackfillSkip: ptr(true), - ChainType: chaintype.NewChainTypeConfig("Optimism"), + ChainType: chaintype.NewConfig("Optimism"), FinalityDepth: ptr[uint32](42), FinalityTagEnabled: ptr[bool](false), FlagsContractAddress: mustAddress("0xae4E781a6218A8031764928E88d457937A954fC3"), diff --git a/core/services/relay/evm/mercury/wsrpc/mocks/mocks.go b/core/services/relay/evm/mercury/wsrpc/mocks/mocks.go index 3a51af02d1c..e202802ea77 100644 --- a/core/services/relay/evm/mercury/wsrpc/mocks/mocks.go +++ b/core/services/relay/evm/mercury/wsrpc/mocks/mocks.go @@ -2,6 +2,7 @@ package mocks import ( "context" + grpc_connectivity "google.golang.org/grpc/connectivity" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" diff --git a/core/services/vrf/extraargs/types.go b/core/services/vrf/extraargs/types.go index eecd0bfa334..540de0f015a 100644 --- a/core/services/vrf/extraargs/types.go +++ b/core/services/vrf/extraargs/types.go @@ -13,7 +13,7 @@ const boolAbiType = `[{ "type": "bool" }]` var extraArgsV1Tag = crypto.Keccak256([]byte("VRF ExtraArgsV1"))[:4] -func FromExtraArgsV1(extraArgs []byte) (nativePayment bool, err error) { +func DecodeV1(extraArgs []byte) (nativePayment bool, err error) { decodedBool, err := utils.ABIDecode(boolAbiType, extraArgs[functionSignatureLength:]) if err != nil { return false, fmt.Errorf("failed to decode 0x%x to bool", extraArgs[functionSignatureLength:]) @@ -25,7 +25,7 @@ func FromExtraArgsV1(extraArgs []byte) (nativePayment bool, err error) { return nativePayment, nil } -func ExtraArgsV1(nativePayment bool) ([]byte, error) { +func EncodeV1(nativePayment bool) ([]byte, error) { encodedArgs, err := utils.ABIEncode(boolAbiType, nativePayment) if err != nil { return nil, err diff --git a/core/services/vrf/v2/coordinator_v2x_interface.go b/core/services/vrf/v2/coordinator_v2x_interface.go index 31621562588..35e8bcd4709 100644 --- a/core/services/vrf/v2/coordinator_v2x_interface.go +++ b/core/services/vrf/v2/coordinator_v2x_interface.go @@ -250,7 +250,7 @@ func (c *coordinatorV2_5) ParseRandomWordsFulfilled(log types.Log) (RandomWordsF } func (c *coordinatorV2_5) RequestRandomWords(opts *bind.TransactOpts, keyHash [32]byte, subID *big.Int, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, payInEth bool) (*types.Transaction, error) { - extraArgs, err := extraargs.ExtraArgsV1(payInEth) + extraArgs, err := extraargs.EncodeV1(payInEth) if err != nil { return nil, err } @@ -569,7 +569,7 @@ func (r *v2_5RandomWordsRequested) CallbackGasLimit() uint32 { } func (r *v2_5RandomWordsRequested) NativePayment() bool { - nativePayment, err := extraargs.FromExtraArgsV1(r.event.ExtraArgs) + nativePayment, err := extraargs.DecodeV1(r.event.ExtraArgs) if err != nil { panic(err) } @@ -1073,7 +1073,7 @@ func (r *RequestCommitment) NativePayment() bool { if r.VRFVersion == vrfcommon.V2 { return false } - nativePayment, err := extraargs.FromExtraArgsV1(r.V2Plus.ExtraArgs) + nativePayment, err := extraargs.DecodeV1(r.V2Plus.ExtraArgs) if err != nil { panic(err) } diff --git a/core/services/vrf/v2/integration_v2_plus_test.go b/core/services/vrf/v2/integration_v2_plus_test.go index 764c950ec35..b4c47c3e0b9 100644 --- a/core/services/vrf/v2/integration_v2_plus_test.go +++ b/core/services/vrf/v2/integration_v2_plus_test.go @@ -966,7 +966,7 @@ func requestAndEstimateFulfillmentCost( requestLog := FindLatestRandomnessRequestedLog(t, uni.rootContract, vrfkey.PublicKey.MustHash(), nil) s, err := proof.BigToSeed(requestLog.PreSeed()) require.NoError(t, err) - extraArgs, err := extraargs.ExtraArgsV1(nativePayment) + extraArgs, err := extraargs.EncodeV1(nativePayment) require.NoError(t, err) proof, rc, err := proof.GenerateProofResponseV2Plus(app.GetKeyStore().VRF(), vrfkey.ID(), proof.PreSeedDataV2Plus{ PreSeed: s, diff --git a/tools/txtar/visitor.go b/tools/txtar/visitor.go index f945ac35237..d96cdc6f0a8 100644 --- a/tools/txtar/visitor.go +++ b/tools/txtar/visitor.go @@ -13,13 +13,13 @@ const ( NoRecurse RecurseOpt = false ) -type TxtarDirVisitor struct { +type DirVisitor struct { rootDir string cb func(path string) error recurse RecurseOpt } -func (d *TxtarDirVisitor) Walk() error { +func (d *DirVisitor) Walk() error { return filepath.WalkDir(d.rootDir, func(path string, de fs.DirEntry, err error) error { if err != nil { return err @@ -52,7 +52,7 @@ func (d *TxtarDirVisitor) Walk() error { }) } -func (d *TxtarDirVisitor) isRootDir(de fs.DirEntry) (bool, error) { +func (d *DirVisitor) isRootDir(de fs.DirEntry) (bool, error) { fi, err := os.Stat(d.rootDir) if err != nil { return false, err @@ -65,8 +65,8 @@ func (d *TxtarDirVisitor) isRootDir(de fs.DirEntry) (bool, error) { return os.SameFile(fi, fi2), nil } -func NewDirVisitor(rootDir string, recurse RecurseOpt, cb func(path string) error) *TxtarDirVisitor { - return &TxtarDirVisitor{ +func NewDirVisitor(rootDir string, recurse RecurseOpt, cb func(path string) error) *DirVisitor { + return &DirVisitor{ rootDir: rootDir, cb: cb, recurse: recurse, From 6dcf219c3e567ba7566b5ae4ad9814d39bba6ed4 Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami <167726375+b-gopalswami@users.noreply.github.com> Date: Thu, 19 Sep 2024 02:13:38 -0400 Subject: [PATCH 03/20] Update to 1.5 RMN contract address (#14485) Co-authored-by: Brandon West <3317895+Bwest981@users.noreply.github.com> --- .../override/mainnet-secondary.toml | 712 ------- .../testconfig/override/mainnet.toml | 1677 +++++++++++------ 2 files changed, 1054 insertions(+), 1335 deletions(-) delete mode 100644 integration-tests/ccip-tests/testconfig/override/mainnet-secondary.toml diff --git a/integration-tests/ccip-tests/testconfig/override/mainnet-secondary.toml b/integration-tests/ccip-tests/testconfig/override/mainnet-secondary.toml deleted file mode 100644 index 7d457774b02..00000000000 --- a/integration-tests/ccip-tests/testconfig/override/mainnet-secondary.toml +++ /dev/null @@ -1,712 +0,0 @@ -[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 index 72695ba7545..f723411eafc 100644 --- a/integration-tests/ccip-tests/testconfig/override/mainnet.toml +++ b/integration-tests/ccip-tests/testconfig/override/mainnet.toml @@ -9,639 +9,1070 @@ CommitStore = '1.2.0' [CCIP.Deployments] Data = """ { - "lane_configs": { + "lane_configs": { + "Arbitrum Mainnet": { + "is_native_fee_token": true, + "fee_token": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", + "arm": "0xC2C5E22a2d9715ed5C5BCC4D8eFf5966cf260744", + "router": "0x141fa059441E0ca23ce184B6A78bafD2A517DdE8", + "price_registry": "0x13015e4E6f839E1Aa1016DF521ea458ecA20438c", + "wrapped_native": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", + "src_contracts": { + "Avalanche Mainnet": { + "on_ramp": "0x05B723f3db92430FbE4395fD03E40Cc7e9D17988", + "deployed_at": 0 + }, + "BSC Mainnet": { + "on_ramp": "0x79f3ABeCe5A3AFFf32D47F4CFe45e7b65c9a2D91", + "deployed_at": 0 + }, + "Base Mainnet": { + "on_ramp": "0x77b60F85b25fD501E3ddED6C1fe7bF565C08A22A", + "deployed_at": 0 + }, + "Blast Mainnet": { + "on_ramp": "0x54480425E9e24138fdF1644a1F70007F25abfB46", + "deployed_at": 0 + }, + "Ethereum Mainnet": { + "on_ramp": "0xCe11020D56e5FDbfE46D9FC3021641FfbBB5AdEE", + "deployed_at": 0 + }, + "Gnosis Mainnet": { + "on_ramp": "0x1216DC856Af47a833254a280A038185F51C1B5c4", + "deployed_at": 0 + }, + "Metis Andromeda": { + "on_ramp": "0x5b23A0a103fC9028363B3BC3577e8Bd45B8E819F", + "deployed_at": 0 + }, + "Mode Mainnet": { + "on_ramp": "0x3920BF474BB50fffb4B77c1e6e66F65210D1D722", + "deployed_at": 0 + }, + "Optimism Mainnet": { + "on_ramp": "0xC09b72E8128620C40D89649019d995Cc79f030C3", + "deployed_at": 0 + }, + "Polygon Mainnet": { + "on_ramp": "0x122F05F49e90508F089eE8D0d868d1a4f3E5a809", + "deployed_at": 0 + }, + "WeMix Mainnet": { + "on_ramp": "0x66a0046ac9FA104eB38B04cfF391CcD0122E6FbC", + "deployed_at": 0 + }, + "ZKSync Mainnet": { + "on_ramp": "0x2C1016053d9873270d71613cA321aE97Fc89201d", + "deployed_at": 0 + } + }, + "dest_contracts": { + "Avalanche Mainnet": { + "off_ramp": "0xe0109912157d5B75ea8b3181123Cf32c73bc9920", + "commit_store": "0xDaa61b8Cd85977820f92d1e749E1D9F55Da6CCEA", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "BSC Mainnet": { + "off_ramp": "0xB1b705c2315fced1B38baE463BE7DDef531e47fA", + "commit_store": "0x310cECbFf14Ad0307EfF762F461a487C1abb90bf", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Base Mainnet": { + "off_ramp": "0xdB19F77F87661f9be0F557cf9a1ebeCf7D8F206c", + "commit_store": "0x6e37f4c82d9A31cc42B445874dd3c3De97AB553f", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Blast Mainnet": { + "off_ramp": "0x449C59F4Ef3b1802DD054dd7837Eb2Ca91aFAB84", + "commit_store": "0x1E0e8B01693A248b3Aa1e5aca36336F9022Ceac0", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Ethereum Mainnet": { + "off_ramp": "0x542ba1902044069330e8c5b36A84EC503863722f", + "commit_store": "0x060331fEdA35691e54876D957B4F9e3b8Cb47d20", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Gnosis Mainnet": { + "off_ramp": "0x0C00414D9dcDB2DA7BF8AF26aE2deb617f09e756", + "commit_store": "0x1d464cd86c5C8358d56281aB31d2213534CCEA13", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Metis Andromeda": { + "off_ramp": "0xeF8dEb0c01f7389AD4ae05DAB30120dba915D53c", + "commit_store": "0xE594a09Aa8bCb55188758826A160615B95A6F3fE", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Mode Mainnet": { + "off_ramp": "0xEDE7ADACFbD27DBEBbE2d6C3BaDf12a634a72Faa", + "commit_store": "0x032B209a6B7a00336047505b55a4cBFBd29eE2c1", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Optimism Mainnet": { + "off_ramp": "0xeeed4D86F3E0e6d32A6Ad29d8De6A0Dc91963A5f", + "commit_store": "0xbbB563c4d98020b9c0f3Cc34c2C0Ef9676806E35", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Polygon Mainnet": { + "off_ramp": "0x9bDA7c8DCda4E39aFeB483cc0B7E3C1f6E0D5AB1", + "commit_store": "0x63a0AeaadAe851b990bBD9dc41f5C1B08b32026d", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "WeMix Mainnet": { + "off_ramp": "0xEEf5Fb4c4953F9cA9ab1f25cE590776AfFc2c455", + "commit_store": "0xD268286A277095a9C3C90205110831a84505881c", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "ZKSync Mainnet": { + "off_ramp": "0x50Fc0de671c775301e1Bdf19C17E778D0f978f6F", + "commit_store": "0x87732C2647168818ED49268EdA8A98C2e62ed744", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "Avalanche Mainnet": { + "is_native_fee_token": true, + "fee_token": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7", + "arm": "0x4f6Ec25f06A114ADD3154DC17fb637F750AdaA31", + "router": "0xF4c7E640EdA248ef95972845a62bdC74237805dB", + "price_registry": "0x2d3b38E0a4DFFDad2A613f7760bE1683F272eA18", + "wrapped_native": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7", + "src_contracts": { + "Arbitrum Mainnet": { + "on_ramp": "0x98f51B041e493fc4d72B8BD33218480bA0c66DDF", + "deployed_at": 0 + }, + "BSC Mainnet": { + "on_ramp": "0x8eaae6462816CB4957184c48B86afA7642D8Bf2B", + "deployed_at": 0 + }, + "Base Mainnet": { + "on_ramp": "0x268fb4311D2c6CB2bbA01CCA9AC073Fb3bfd1C7c", + "deployed_at": 0 + }, + "Ethereum Mainnet": { + "on_ramp": "0xD0701FcC7818c31935331B02Eb21e91eC71a1704", + "deployed_at": 0 + }, + "Gnosis Mainnet": { + "on_ramp": "0xBd0B9317F6AaA1085993F7b4CD468dE7A6428722", + "deployed_at": 0 + }, + "Optimism Mainnet": { + "on_ramp": "0x8629008887E073260c5434D6CaCFc83C3001d211", + "deployed_at": 0 + }, + "Polygon Mainnet": { + "on_ramp": "0x97500490d9126f34cf9aA0126d64623E170319Ef", + "deployed_at": 0 + }, + "WeMix Mainnet": { + "on_ramp": "0x9b1ed9De069Be4d50957464b359f98eD0Bf34dd5", + "deployed_at": 0 + } + }, + "dest_contracts": { + "Arbitrum Mainnet": { + "off_ramp": "0x770b1375F86E7a9bf30DBe3F97bea67193dC9135", + "commit_store": "0x23E2b34Ce8e12c53f8a39AD4b3FFCa845f8E617C", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "BSC Mainnet": { + "off_ramp": "0x83F53Fc798FEbfFbdF84830AD403b9989187a06C", + "commit_store": "0xD8ceCE2D7794385E00Ce3EF94550E732b0A0B959", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Base Mainnet": { + "off_ramp": "0x4d6A796Bc85dcDF41ce9AaEB50B094C6b589748f", + "commit_store": "0xc4C4358FA01a04D6c6FE3b96a351946d4c2715C2", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Ethereum Mainnet": { + "off_ramp": "0x5B833BD6456c604Eb396C0fBa477aD49e82B1A2a", + "commit_store": "0x23E23958D220B774680f91c2c91a6f2B2f610d7e", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Gnosis Mainnet": { + "off_ramp": "0xDE7ebf1Dc753D916A9fbEC4ae521Ee74EC2d0B5f", + "commit_store": "0x2dbc917b4DD455532015949c3103B64fcDB891b2", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Optimism Mainnet": { + "off_ramp": "0xb68A3EE8bD0A09eE221cf1859Dd5a4d5765188Fe", + "commit_store": "0x83DCeeCf822981F9F8552925eEfd88CAc1905dEA", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Polygon Mainnet": { + "off_ramp": "0x19250aBE66B88F214d02B6f3BF80F4118290C619", + "commit_store": "0x87A0935cE6254dB1252bBac90d1D07D04846aDCA", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "WeMix Mainnet": { + "off_ramp": "0x317dE8bc5c3292E494b6496586696d4966A922B0", + "commit_store": "0x97Fbf3d6DEac16adC721aE9187CeEa1e610aC7Af", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "BSC Mainnet": { + "is_native_fee_token": true, + "fee_token": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", + "arm": "0x56491A98199aD2e687Ea9D0cFB7b4AC57B4980Fc", + "router": "0x34B03Cb9086d7D758AC55af71584F81A598759FE", + "price_registry": "0x18C3D917D55Bc1784a3d4729AA3e2C1ecd662fFd", + "wrapped_native": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", + "src_contracts": { + "Arbitrum Mainnet": { + "on_ramp": "0x2788b46BAcFF49BD89562e6bA5c5FBbbE5Fa92F7", + "deployed_at": 0 + }, + "Avalanche Mainnet": { + "on_ramp": "0x6aa72a998859eF93356c6521B72155D355D0Cfd2", + "deployed_at": 0 + }, + "Base Mainnet": { + "on_ramp": "0x70bC7f7a6D936b289bBF5c0E19ECE35B437E2e36", + "deployed_at": 0 + }, + "Blast Mainnet": { + "on_ramp": "0x02082b23D35d2670B8a636A431F3C30AF9d21e07", + "deployed_at": 0 + }, + "Ethereum Mainnet": { + "on_ramp": "0x0Bf40b034872D0b364f3DCec04C7434a4Da1C8d9", + "deployed_at": 0 + }, + "Gnosis Mainnet": { + "on_ramp": "0xAc9fE4179816077674d769698306CE6A7C6A1096", + "deployed_at": 0 + }, + "Mode Mainnet": { + "on_ramp": "0x4A83dA46c148AB5941a379b4cA49f42d14281C78", + "deployed_at": 0 + }, + "Optimism Mainnet": { + "on_ramp": "0x4FEB11A454C9E8038A8d0aDF599Fe7612ce114bA", + "deployed_at": 0 + }, + "Polygon Mainnet": { + "on_ramp": "0x6bD4754D86fc87FE5b463D368f26a3587a08347c", + "deployed_at": 0 + }, + "WeMix Mainnet": { + "on_ramp": "0x1467fF8f249f5bc604119Af26a47035886f856BE", + "deployed_at": 0 + } + }, + "dest_contracts": { + "Arbitrum Mainnet": { + "off_ramp": "0x3DA330fd8Ef10d93cFB7D4f8ecE7BC1F10811feC", + "commit_store": "0x86D55Ff492cfBBAf0c0D42D4EE615144E78b3D02", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Avalanche Mainnet": { + "off_ramp": "0x37a6fa55fe61061Ae97bF7314Ae270eCF71c5ED3", + "commit_store": "0x1f558F6dcf0224Ef1F78A24814FED548B9602c80", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Base Mainnet": { + "off_ramp": "0x574c697deab06B805D8780898B3F136a1F4892Dc", + "commit_store": "0x002B164b1dcf4E92F352DC625A01Be0E890EdEea", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Blast Mainnet": { + "off_ramp": "0x6500EDFBD27d34b7B69D0D45865ddaC4A1ceafE1", + "commit_store": "0x3A328B3fA852409415c15271442EFE4c77C04992", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Ethereum Mainnet": { + "off_ramp": "0x181Bb1E97b0bDD1D85E741ad0943552D3682cc35", + "commit_store": "0x3fF27A34fF0FA77921C3438e67f58da1a83e9Ce1", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Gnosis Mainnet": { + "off_ramp": "0xBE9b0cc569E970dAb953d336c670fc6b7c856c19", + "commit_store": "0xEe89CC6C2236d3b99C2D9c0b3b911690F757FadF", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Mode Mainnet": { + "off_ramp": "0x6C702159daA4DEbae32E294c584B1EaF2356cB1A", + "commit_store": "0x73C8d1E9e240331E3345c6fBe6CDFC71B742B69C", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Optimism Mainnet": { + "off_ramp": "0xE7E080C8d62d595a223C577C7C8d1f75d9A5E664", + "commit_store": "0xF4d53346bDb6d393C74B0B72Aa7D6689a3eAad79", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Polygon Mainnet": { + "off_ramp": "0x26af2046Da85d7f6712D5edCa81B9E3b2e7A60Ab", + "commit_store": "0x4C1dA405a789AC2853A69D8290B8B9b47a0374F8", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "WeMix Mainnet": { + "off_ramp": "0xC027C5AEb230008c243Be463A73571e581F94c13", + "commit_store": "0x2EB426C8C54D740d1FC856eB3Ff96feA03957978", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "Base Mainnet": { + "is_native_fee_token": true, + "fee_token": "0x4200000000000000000000000000000000000006", + "arm": "0x91cB19E7c4Ba9B08CF544cDc9143042150B007C3", + "router": "0x881e3A65B4d4a04dD529061dd0071cf975F58bCD", + "price_registry": "0x1bA15c57c8b74cD32443D7583E7f6d7c638aCf46", + "wrapped_native": "0x4200000000000000000000000000000000000006", + "src_contracts": { "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" - } - } + "on_ramp": "0x1E5Ca70d1e7A1B26061125738a880BBeA42FeB21", + "deployed_at": 0 }, "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" - } - } + "on_ramp": "0xBE5a9E336D9614024B4Fa10D8112671fc9A42d96", + "deployed_at": 0 + }, + "BSC Mainnet": { + "on_ramp": "0xdd4Fb402d41Beb0eEeF6CfB1bf445f50bDC8c981", + "deployed_at": 0 + }, + "Blast Mainnet": { + "on_ramp": "0xCCC32e2794EaD73f0a0a514Ac1c78D048968ab81", + "deployed_at": 0 + }, + "Ethereum Mainnet": { + "on_ramp": "0xDEA286dc0E01Cb4755650A6CF8d1076b454eA1cb", + "deployed_at": 0 + }, + "Gnosis Mainnet": { + "on_ramp": "0xcDD0e963E0708a4E936202396983E458cFA4A363", + "deployed_at": 0 + }, + "Mode Mainnet": { + "on_ramp": "0x626aCCbDDD73532df1caEDb5628Fdc40C5f429Ba", + "deployed_at": 0 + }, + "Optimism Mainnet": { + "on_ramp": "0xd952FEAcDd5919Cc5E9454b53bF45d4E73dD6457", + "deployed_at": 0 + }, + "Polygon Mainnet": { + "on_ramp": "0x3DB8Bea142e41cA3633890d0e5640F99a895D6A5", + "deployed_at": 0 + } + }, + "dest_contracts": { + "Arbitrum Mainnet": { + "off_ramp": "0x8531E63aE9279a1f0D09eba566CD1b092b95f3D5", + "commit_store": "0x327E13f54c7871a2416006B33B4822eAAD357916", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Avalanche Mainnet": { + "off_ramp": "0x8345F2fF67e5A65e85dc955DE1414832608E00aD", + "commit_store": "0xd0b13be4c53A6262b47C5DDd36F0257aa714F562", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "BSC Mainnet": { + "off_ramp": "0x48a51f5D38BE630Ddd6417Ea2D9052B8efc91a18", + "commit_store": "0xF97127e77252284EC9D4bc13C247c9D1A99F72B0", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Blast Mainnet": { + "off_ramp": "0x15F54FDd37ccC8E5a0b64633C95Ef8209Fd86401", + "commit_store": "0x52b5b4f3Cc50E38f736f23897f192430E131ccB8", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Ethereum Mainnet": { + "off_ramp": "0xEC0cFe335a4d53dBA70CB650Ab56eEc32788F0BB", + "commit_store": "0x0ae3c2c7FB789bd05A450CD3075D11f6c2Ca4F77", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Gnosis Mainnet": { + "off_ramp": "0xA24D3Bc3A59798a57AF58f69c89DC1C8aFD78F18", + "commit_store": "0x672dbdC3aF7eE37436fe101531D33266D85F33c9", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Mode Mainnet": { + "off_ramp": "0xFC30bFe46b11D4E25C6f7492fd064A70FbF18848", + "commit_store": "0xaeDBe55633F74A291F0A43Daa0Fd719615b78363", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Optimism Mainnet": { + "off_ramp": "0xf50c0d2a8B6Db60f1D93E60f03d0413D56153E4F", + "commit_store": "0x16f72C15165f7C9d74c12fDF188E399d4d3724e4", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Polygon Mainnet": { + "off_ramp": "0x75F29f058b31106F99caFdc17c9b26ADfcC7b5D7", + "commit_store": "0xb719616E732581B570232DfB13Ca49D27667Af9f", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "Blast Mainnet": { + "is_native_fee_token": true, + "fee_token": "0x4300000000000000000000000000000000000004", + "arm": "0x96aFe20249C4f6f55d2fe0E792138f6a4dC566A4", + "router": "0x12e0B8E349C6fb7E6E40713E8125C3cF1127ea8C", + "price_registry": "0x4f66d9e65af0d3DC27897E29f571f933291bb07c", + "wrapped_native": "0x4300000000000000000000000000000000000004", + "src_contracts": { + "Arbitrum Mainnet": { + "on_ramp": "0x42E1f5f5ACCe6e4971D9B9468D7A9Abed8D69DdD", + "deployed_at": 0 + }, + "BSC Mainnet": { + "on_ramp": "0x9c98d7aE731b0A53bedffBc1a12d9d43501Ea464", + "deployed_at": 0 }, "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" - } - } + "on_ramp": "0x955f139225F5d7021EB911ED2787a795f71E5eb6", + "deployed_at": 0 + }, + "Ethereum Mainnet": { + "on_ramp": "0xBD9bf9AA79adF083BB7100848Eb15F4e8282E27e", + "deployed_at": 0 + } + }, + "dest_contracts": { + "Arbitrum Mainnet": { + "off_ramp": "0x01A38cd2da195C704bA192fCCDddd8986cb7EdE9", + "commit_store": "0xab6D69db1C1E9B97a26eB3983b0878AdeD248200", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" }, "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" - } - } + "off_ramp": "0xabC7Dffb2590c44a201EC7532382e1fc01Cd9eEb", + "commit_store": "0xA3086bf1D609d8e8028E8339e4aa4362C7da339D", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Base Mainnet": { + "off_ramp": "0x0406F8f66C10Da99ff518bc2242e0Ec486a2c787", + "commit_store": "0xc6A97d753a3001e0B893e5FA2b0ec3d623af6C20", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" }, "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" - } - } + "off_ramp": "0x4e0092bBC8EfAb6Eca295caB66986193b90a1Bb9", + "commit_store": "0xd7cA96B58EE33FdB3aa1392c30eD02645b1F28e2", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "Celo": { + "is_native_fee_token": true, + "fee_token": "0x2021B12D8138e2D63cF0895eccABC0DFc92416c6", + "arm": "0x832Ca6A279D8F8c695986086B35c70D4E0c817CC", + "router": "0xfB48f15480926A4ADf9116Dca468bDd2EE6C5F62", + "price_registry": "0xD9FcEEA20dBB3Dfb91763B301819C9666429DC26", + "wrapped_native": "0x2021B12D8138e2D63cF0895eccABC0DFc92416c6", + "src_contracts": { + "Ethereum Mainnet": { + "on_ramp": "0x27C96A8a2f70a8408aD6c620717a3bDaA54bb10b", + "deployed_at": 0 + } + }, + "dest_contracts": { + "Ethereum Mainnet": { + "off_ramp": "0x90902C0AEE857F3A42f2beBEa38724cE7b7a0cff", + "commit_store": "0x25adA90B241143DD5Df04Fb06C1fF6E7f7624ad9", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "Ethereum Mainnet": { + "is_native_fee_token": true, + "fee_token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "arm": "0xdCD48419bD5Cd9d1b097695F2af4Ee125aADF84F", + "router": "0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D", + "price_registry": "0x020082A7a9c2510e1921116001152DEE4da81985", + "wrapped_native": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "src_contracts": { + "Arbitrum Mainnet": { + "on_ramp": "0x925228D7B82d883Dde340A55Fe8e6dA56244A22C", + "deployed_at": 0 }, - "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" - } - } + "Avalanche Mainnet": { + "on_ramp": "0x3df8dAe2d123081c4D5E946E655F7c109B9Dd630", + "deployed_at": 0 + }, + "BSC Mainnet": { + "on_ramp": "0x91D25A56Db77aD5147437d8B83Eb563D46eBFa69", + "deployed_at": 0 + }, + "Base Mainnet": { + "on_ramp": "0xe2c2AB221AA0b957805f229d2AA57fBE2f4dADf7", + "deployed_at": 0 + }, + "Blast Mainnet": { + "on_ramp": "0x4545F9a17DA50110632C14704a15d893BF9CBD27", + "deployed_at": 0 + }, + "Celo": { + "on_ramp": "0xEd5bE9508ae56531cc0EDe6A3bD588Eb9E2e3cfa", + "deployed_at": 0 + }, + "Gnosis Mainnet": { + "on_ramp": "0xF538dA6c673A30338269655f4e019B71ba58CFd4", + "deployed_at": 0 + }, + "Metis Andromeda": { + "on_ramp": "0xa5ef33B57dD8B653F9A9EA7114f46376d18264aC", + "deployed_at": 0 + }, + "Mode Mainnet": { + "on_ramp": "0x466a078d17e3706a9414ACc48029EE9Bae4C9b65", + "deployed_at": 0 + }, + "Optimism Mainnet": { + "on_ramp": "0x86B47d8411006874eEf8E4584BdFD7be8e5549d1", + "deployed_at": 0 + }, + "Polygon Mainnet": { + "on_ramp": "0x35F0ca9Be776E4B38659944c257bDd0ba75F1B8B", + "deployed_at": 0 + }, + "WeMix Mainnet": { + "on_ramp": "0xCbE7e5DA76dC99Ac317adF6d99137005FDA4E2C4", + "deployed_at": 0 + }, + "ZKSync Mainnet": { + "on_ramp": "0xD54C93A99CBCb8D865E13DA321B540171795A89f", + "deployed_at": 0 + } + }, + "dest_contracts": { + "Arbitrum Mainnet": { + "off_ramp": "0xeFC4a18af59398FF23bfe7325F2401aD44286F4d", + "commit_store": "0x9B2EEd6A1e16cB50Ed4c876D2dD69468B21b7749", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Avalanche Mainnet": { + "off_ramp": "0x569940e02D4425eac61A7601632eC00d69f75c17", + "commit_store": "0x2aa101BF99CaeF7fc1355D4c493a1fe187A007cE", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "BSC Mainnet": { + "off_ramp": "0x7Afe7088aff57173565F4b034167643AA8b9171c", + "commit_store": "0x87c55D48DF6EF7B08153Ab079e76bFEcbb793D75", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Base Mainnet": { + "off_ramp": "0xdf85c8381954694E74abD07488f452b4c2Cddfb3", + "commit_store": "0x8DC27D621c41a32140e22E2a4dAf1259639BAe04", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Blast Mainnet": { + "off_ramp": "0x1a904DbbaDdE629a1460e2F6E2E485Ce06Ed7599", + "commit_store": "0x3CB2A81bb8a188C5353CdFa9994ed8666556FC53", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Celo": { + "off_ramp": "0xd5083684eE92dDeA117636ae5E2F1cb7fE4dfd46", + "commit_store": "0x831097033C88c82a7F1897b168Aa88cC44540C8f", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Gnosis Mainnet": { + "off_ramp": "0xE93ec2A57e38C8541c893348cCafEAB01F7D47d4", + "commit_store": "0x118a9389960F86390A4F14ce4C95D6ff076C6bFC", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Metis Andromeda": { + "off_ramp": "0xCe6364dBe64D2789D916180131fAda2ABFF702E8", + "commit_store": "0x3d8a95adA63D406ee8232562AbD83CEdb0B90466", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Mode Mainnet": { + "off_ramp": "0xE8af3b68eDfFf65Ce48648009982380701f09B92", + "commit_store": "0x76264869a3eBF51a59FCa5ABa84ee2867c7F190e", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Optimism Mainnet": { + "off_ramp": "0xB095900fB91db00E6abD247A5A5AD1cee3F20BF7", + "commit_store": "0x4af4B497c998007eF83ad130318eB2b925a79dc8", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Polygon Mainnet": { + "off_ramp": "0x0af338F0E314c7551bcE0EF516d46d855b0Ee395", + "commit_store": "0xD37a60E8C36E802D2E1a6321832Ee85556Beeb76", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "WeMix Mainnet": { + "off_ramp": "0x3a129e6C18b23d18BA9E6Aa14Dc2e79d1f91c6c5", + "commit_store": "0x31f6ab382DDeb9A316Ab61C3945a5292a50a89AB", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "ZKSync Mainnet": { + "off_ramp": "0xb368c8946D9fa5A497cDe1Dff7213f9CdfD143Bf", + "commit_store": "0xa4d264470a67D9f6682EE12Bdc9c35Df44e3F194", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "Gnosis Mainnet": { + "is_native_fee_token": true, + "fee_token": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", + "arm": "0x2ab5ff904CFFdD37f19cC34597cF425916F2DAcA", + "router": "0x4aAD6071085df840abD9Baf1697d5D5992bDadce", + "price_registry": "0xec00a50EFb62F5f686E0FdEFDD6e10744dc53cAD", + "wrapped_native": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", + "src_contracts": { + "Arbitrum Mainnet": { + "on_ramp": "0x7A36511202f54a8A3Bc62Cc1df24bd391f7c9864", + "deployed_at": 0 + }, + "Avalanche Mainnet": { + "on_ramp": "0x732753869bc6bB07Ec81A403F926bbF6fC2FeaE2", + "deployed_at": 0 + }, + "BSC Mainnet": { + "on_ramp": "0xD5d33bc0BF395B39514B7f9f8F66ebc9D8e650Cb", + "deployed_at": 0 + }, + "Base Mainnet": { + "on_ramp": "0x400eFb50480a73FEc02b115b53F0Ec6EcFf03C67", + "deployed_at": 0 + }, + "Ethereum Mainnet": { + "on_ramp": "0x0F246651F1c2275B4E14d8ae166D1fd3Af05c405", + "deployed_at": 0 + }, + "Optimism Mainnet": { + "on_ramp": "0x391516732884d3F8Eec3301C19b819E6e6044C17", + "deployed_at": 0 + }, + "Polygon Mainnet": { + "on_ramp": "0x566c7A2Cb557c36082301B97E998721D14E4bF7d", + "deployed_at": 0 + } + }, + "dest_contracts": { + "Arbitrum Mainnet": { + "off_ramp": "0x1bee1FD97824288a36B725f9CF20E07A67d5113b", + "commit_store": "0xB3a48e8664C5dE26822ae44577b100b717C36a54", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Avalanche Mainnet": { + "off_ramp": "0x633c19cCD7A818770f7BF59eB9C5AB632CDbc4D5", + "commit_store": "0xbbC073fb2D424eA45A571cc4dd91745E45d0aC73", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "BSC Mainnet": { + "off_ramp": "0x4D90524de5783257fd64d1a20689a5b9Bad25de0", + "commit_store": "0xAae8De9f1B7e2FFF0563c2BBf0c69593BD517b52", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Base Mainnet": { + "off_ramp": "0x9118303DE7f4342F9B057f6EC1Be282aa543D99C", + "commit_store": "0xa75f463b8a1d8bf7694Ac13E02938894F45eFbaA", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Ethereum Mainnet": { + "off_ramp": "0xFF61E57A2eE83FA262006C2DaF0D5fB2b36F3070", + "commit_store": "0xF433De9A293553c133E2dB90e226c2F2911f435C", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Optimism Mainnet": { + "off_ramp": "0x9D3aA479525a5BcE776dD83769e9F9b5B4dD4193", + "commit_store": "0x2B721632693A8BbABa3bA5F125C8cD33D66F28F7", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Polygon Mainnet": { + "off_ramp": "0x9714098CDdAc380D4443293C55B6CBf6D6bbDbEb", + "commit_store": "0x4338f204C7698eE678d6c44117503f812ca1FA69", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "Kroma Mainnet": { + "is_native_fee_token": true, + "fee_token": "0x4200000000000000000000000000000000000001", + "arm": "0xB558b375D1D8a1aE2c3d5bBe43634BcF4d0d108c", + "router": "0xE93E8B0d1b1CEB44350C8758ed1E2799CCee31aB", + "price_registry": "0x8155B4710e7bbC90924E957104F94Afd4f95Eca2", + "wrapped_native": "0x4200000000000000000000000000000000000001", + "src_contracts": { + "WeMix Mainnet": { + "on_ramp": "0x3C5Ab46fA1dB1dECD854224654313a69bf9fcAD3", + "deployed_at": 0 + } + }, + "dest_contracts": { + "WeMix Mainnet": { + "off_ramp": "0x2B555774B3D1dcbcd76efb7751F3c5FbCFABC5C4", + "commit_store": "0x213124614aAf31eBCE7c612A12aac5f8aAD77DE4", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "Metis Andromeda": { + "is_native_fee_token": true, + "fee_token": "0x75cb093E4D61d2A2e65D8e0BBb01DE8d89b53481", + "arm": "0xC4BFAc3D31C524A4958c5d5d1e68394d8DEbbE69", + "router": "0x7b9FB8717D306e2e08ce2e1Efa81F026bf9AD13c", + "price_registry": "0xe1A7e2f9E88a72aF3E4790f33FfcDEa43d5eCC7B", + "wrapped_native": "0x75cb093E4D61d2A2e65D8e0BBb01DE8d89b53481", + "src_contracts": { + "Arbitrum Mainnet": { + "on_ramp": "0x87353b87A373E1551D27EDacDaC1644741c6499F", + "deployed_at": 0 + }, + "Ethereum Mainnet": { + "on_ramp": "0xE43f9eD3146d76E627C2504E5140005027992De6", + "deployed_at": 0 + } + }, + "dest_contracts": { + "Arbitrum Mainnet": { + "off_ramp": "0x2cc33de75dAFDb3F8F4f24244a9C420374e2C001", + "commit_store": "0x67fE38dB73be154a1f1a63221F898B9d5EE4eF63", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Ethereum Mainnet": { + "off_ramp": "0xc2B1A8c931582D041ba5fF30AEB9fA828B30754d", + "commit_store": "0x90073Ea7A1Ee4Fe5d638B4216Bc60479Eba52001", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "Mode Mainnet": { + "is_native_fee_token": true, + "fee_token": "0x4200000000000000000000000000000000000006", + "arm": "0x77EAF440c5d24e25D1834CBBF623bFd83b8b5dA1", + "router": "0x24C40f13E77De2aFf37c280BA06c333531589bf1", + "price_registry": "0xffDEc5d752dd1fa1f56C236183ACB022e5D9d79e", + "wrapped_native": "0x4200000000000000000000000000000000000006", + "src_contracts": { + "Arbitrum Mainnet": { + "on_ramp": "0x65Ad802d80aD6a96C5a4bc9e57E16099de99Dc7F", + "deployed_at": 0 + }, + "BSC Mainnet": { + "on_ramp": "0x8C5149ff7Cfd99dd561caE9B7abFAA0Ef79eAbeC", + "deployed_at": 0 + }, + "Base Mainnet": { + "on_ramp": "0x71dB32eF442c29d8cbf72a9AFcb1Ef12B35b0BF4", + "deployed_at": 0 + }, + "Ethereum Mainnet": { + "on_ramp": "0xbD5F9C193a7fEF5D578C55Ddfe4d08d6BCc15648", + "deployed_at": 0 }, "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" - } - } + "on_ramp": "0x659303e8d4306D3ea8676FB034d56FB6f37E19d9", + "deployed_at": 0 + } + }, + "dest_contracts": { + "Arbitrum Mainnet": { + "off_ramp": "0x8d3E1b15ebC96cec1ffc092cEcAeA6c1DD00aF9b", + "commit_store": "0x1f1DEa0210aE346A20E270a1C3355d99b0B949D2", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "BSC Mainnet": { + "off_ramp": "0x7a57670Fa0Cf1Bc2665a1Ae0f5031b9f5a43dD3a", + "commit_store": "0x18ffb74D94175d00D8bB67B70737dE2cE45eed07", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Base Mainnet": { + "off_ramp": "0xEfa90cE6289A2777cd5B8fb991B2D0Be44cA5067", + "commit_store": "0xACa5f0942Bb7fF297A7c25E8364373702D81bb3f", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Ethereum Mainnet": { + "off_ramp": "0xdF8f09AB4DfB49dEC8a0B8b7f1B7F4134252D3e9", + "commit_store": "0x8Ae635d264f20f1dbC0dea03712C194AdbeF50D1", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Optimism Mainnet": { + "off_ramp": "0xE4D6AAF678b986D3E6B7A85FA33d0519716a5525", + "commit_store": "0xBF80E30c8c013Ec0d05e2a959CF8000407C813EC", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "Optimism Mainnet": { + "is_native_fee_token": true, + "fee_token": "0x4200000000000000000000000000000000000006", + "arm": "0x1c51b6D5BFcFB7ee82C80949DFD146dB157a7E49", + "router": "0x3206695CaE29952f4b0c22a169725a865bc8Ce0f", + "price_registry": "0x9270AAA75F4B9038f4c25fEc665B02a150a90361", + "wrapped_native": "0x4200000000000000000000000000000000000006", + "src_contracts": { + "Arbitrum Mainnet": { + "on_ramp": "0x0C9BE7Cfd12c735E5aaE047C1dCB845d54E518C3", + "deployed_at": 0 + }, + "Avalanche Mainnet": { + "on_ramp": "0xD0D3E757bFBce7ae1881DDD7F6d798DDcE588445", + "deployed_at": 0 + }, + "BSC Mainnet": { + "on_ramp": "0xa3c9544B82846C45BE37593d5d9ACffbE61BF3A6", + "deployed_at": 0 + }, + "Base Mainnet": { + "on_ramp": "0x0b1760A8112183303c5526C6b24569fd3A274f3B", + "deployed_at": 0 + }, + "Ethereum Mainnet": { + "on_ramp": "0x55183Db1d2aE0b63e4c92A64bEF2CBfc2032B127", + "deployed_at": 0 + }, + "Gnosis Mainnet": { + "on_ramp": "0x14aA3CC03583aA557DBca4ce72288Cc5F37DDE34", + "deployed_at": 0 + }, + "Mode Mainnet": { + "on_ramp": "0x034eA573B049210315110f7eA11c9618E32F08Ae", + "deployed_at": 0 + }, + "Polygon Mainnet": { + "on_ramp": "0x6B57145e322c877E7D91Ed8E31266eB5c02F7EfC", + "deployed_at": 0 + }, + "WeMix Mainnet": { + "on_ramp": "0x82e9f4C5ec4a84E310d60D462a12042E5cbA0954", + "deployed_at": 0 + } + }, + "dest_contracts": { + "Arbitrum Mainnet": { + "off_ramp": "0xaC8C94242aa8234Bf89682aBcDDf805AE8cff61D", + "commit_store": "0x55028780918330FD00a34a61D9a7Efd3f43ca845", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Avalanche Mainnet": { + "off_ramp": "0x8dc6490A6204dF846BaBE809cB695ba17Df1F9B1", + "commit_store": "0xA190660787B6B183Dd82B243eA10e609327c7308", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "BSC Mainnet": { + "off_ramp": "0xE14501F2838F2fA1Ceb52E78ABdA289EcE1705EA", + "commit_store": "0xa8DD25B29787527Df283211C24Ac72B17150A696", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Base Mainnet": { + "off_ramp": "0xBAE6560eCa9B77Cb047158C783e36F7735C86037", + "commit_store": "0x6168aDF58e1Ad446BaD45c6275Bef60Ef4FFBAb8", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Ethereum Mainnet": { + "off_ramp": "0xd2D98Be6a1C241e86C807e51cED6ABb51d044203", + "commit_store": "0x4d75A5cE454b264b187BeE9e189aF1564a68408D", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Gnosis Mainnet": { + "off_ramp": "0x4358640A2419119DBe0933b5F2c288c3EB2c082C", + "commit_store": "0x44d1a05ef6e54a3CB35a1497303bA272f15f45ed", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Mode Mainnet": { + "off_ramp": "0xDf9717d724828537902Fb0c3B7C56c641463Fa38", + "commit_store": "0x8aEFF283381914E07Fc371601D59648ab6D2C0B1", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" }, "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" - } - } + "off_ramp": "0x7c6221880A1D62506b1A08Dab3Bf695A49AcDD22", + "commit_store": "0x0684076EE3595221861C50cDb9Cb66402Ec11Cb9", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" }, "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" - } - } + "off_ramp": "0x3e5B3b7559D39563a74434157b31781322dA712D", + "commit_store": "0x7954372FF6f80908e5A2dC2a19d796A1005f91D2", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "Polygon Mainnet": { + "is_native_fee_token": true, + "fee_token": "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270", + "arm": "0x569a295a09634Ac9414c3efe4E8931986d68F937", + "router": "0x849c5ED5a80F5B408Dd4969b78c2C8fdf0565Bfe", + "price_registry": "0x30D873664Ba766C983984C7AF9A921ccE36D34e1", + "wrapped_native": "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270", + "src_contracts": { + "Arbitrum Mainnet": { + "on_ramp": "0xD16D025330Edb91259EEA8ed499daCd39087c295", + "deployed_at": 0 + }, + "Avalanche Mainnet": { + "on_ramp": "0x5FA30697e90eB30954895c45b028F7C0dDD39b12", + "deployed_at": 0 + }, + "BSC Mainnet": { + "on_ramp": "0xF5b5A2fC11BF46B1669C3B19d98B19C79109Dca9", + "deployed_at": 0 + }, + "Base Mainnet": { + "on_ramp": "0x20B028A2e0F6CCe3A11f3CE5F2B8986F932e89b4", + "deployed_at": 0 + }, + "Ethereum Mainnet": { + "on_ramp": "0xFd77c53AA4eF0E3C01f5Ac012BF7Cc7A3ECf5168", + "deployed_at": 0 + }, + "Gnosis Mainnet": { + "on_ramp": "0x4616621704C81801A56D29c961F9395ee153d46C", + "deployed_at": 0 + }, + "Optimism Mainnet": { + "on_ramp": "0x3111cfbF5e84B5D9BD952dd8e957f4Ca75f728Cf", + "deployed_at": 0 + }, + "WeMix Mainnet": { + "on_ramp": "0x5060eF647a1F66BE6eE27FAe3046faf8D53CeB2d", + "deployed_at": 0 + } + }, + "dest_contracts": { + "Arbitrum Mainnet": { + "off_ramp": "0xa8a9eDa2867c2E0CE0d5ECe273961F1EcC3CC25B", + "commit_store": "0xbD4480658dca8496a65046dfD1BDD44EF897Bdb5", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Avalanche Mainnet": { + "off_ramp": "0xB9e3680639c9F0C4e0b02FD81C445094426244Ae", + "commit_store": "0x8c63d4e67f7c4af6FEd2f56A34fB4e01CB807CFF", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "BSC Mainnet": { + "off_ramp": "0x592773924741F0Da889a0dfdab71171Dd11E054C", + "commit_store": "0xEC4d35E1A85f770f4D93BA43a462c9d87Ef7017e", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Base Mainnet": { + "off_ramp": "0xD0FA7DE2D18A0c59D3fD7dfC7aB4e913C6Aa7b68", + "commit_store": "0xF88053B9DAC8Dd3039a4eFa8639159aaa3F2D4Cb", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Ethereum Mainnet": { + "off_ramp": "0x45320085fF051361D301eC1044318213A5387A15", + "commit_store": "0x4Dc771B5ef21ef60c33e2987E092345f2b63aE08", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Gnosis Mainnet": { + "off_ramp": "0x0A04eC196454825d361886cf4FA113A948164Ef8", + "commit_store": "0x74b72633b63A8f4374a12DB6F609305BC5a1b2d5", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Optimism Mainnet": { + "off_ramp": "0xBa754ecd3CFA7E9093F688EAc3860cf9D07Fc0AC", + "commit_store": "0x04C0D5302E3D8Ca0A0019141a52a23B59cdb70e4", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "WeMix Mainnet": { + "off_ramp": "0xd7c877ea02310Cce9278D9A048Aa1Bb9aF72F00d", + "commit_store": "0x92A1C927E8E10Ab6A40E5A5154e2300D278d1a67", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "WeMix Mainnet": { + "is_native_fee_token": true, + "fee_token": "0x7D72b22a74A216Af4a002a1095C8C707d6eC1C5f", + "arm": "0xdBa0afF04bf63Ba6b75DEC94d1A934a367CAA782", + "router": "0x7798b795Fde864f4Cd1b124a38Ba9619B7F8A442", + "price_registry": "0x252863688762aD86868D3d3076233Eacd80c7055", + "wrapped_native": "0x7D72b22a74A216Af4a002a1095C8C707d6eC1C5f", + "src_contracts": { + "Arbitrum Mainnet": { + "on_ramp": "0x9aBfd6f4C865610692AB6fb1Be862575809fFabf", + "deployed_at": 0 + }, + "Avalanche Mainnet": { + "on_ramp": "0xbE0Cfae74677F8dd16a246a3a5c8cbB1973118f4", + "deployed_at": 0 + }, + "BSC Mainnet": { + "on_ramp": "0x56657ec4D15C71f7F3C17ba2b21C853A24Dc5381", + "deployed_at": 0 + }, + "Ethereum Mainnet": { + "on_ramp": "0x190bcE84CF2d500B878966F4Cf98a50d78f2675E", + "deployed_at": 0 + }, + "Kroma Mainnet": { + "on_ramp": "0x47E9AE0A815C94836202E696748A5d5476aD8735", + "deployed_at": 0 + }, + "Optimism Mainnet": { + "on_ramp": "0x70f3b0FD7e6a4B9B623e9AB859604A9EE03e48BD", + "deployed_at": 0 + }, + "Polygon Mainnet": { + "on_ramp": "0x777058C1e1dcE4eB8001F38631a1cd9450816e5a", + "deployed_at": 0 } + }, + "dest_contracts": { + "Arbitrum Mainnet": { + "off_ramp": "0x2ba68a395B72a6E3498D312efeD755ed2f3CF223", + "commit_store": "0xdAeC234DA83F68707Bb8AcB2ee6a01a5FD4c2391", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Avalanche Mainnet": { + "off_ramp": "0xFac907F9a1087B846Faa75A14C5d34A8639233d8", + "commit_store": "0xF2812063446c7deD2CA306c67A68364BdDcbEfc5", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "BSC Mainnet": { + "off_ramp": "0x6ec9ca4Cba62cA17c55F05ad2000B46192f02035", + "commit_store": "0x84534BE763366a69710E119c100832955795B34B", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Ethereum Mainnet": { + "off_ramp": "0xF92Fa796F5307b029c65CA26f322a6D86f211194", + "commit_store": "0xbeC110FF43D52be2066B06525304A9924E16b73b", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Kroma Mainnet": { + "off_ramp": "0xF886d8DC64E544af4835cbf91e5678A54D95B80e", + "commit_store": "0x8794C9534658fdCC44f2FF6645Bf31cf9F6d2d5D", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Optimism Mainnet": { + "off_ramp": "0x87220D01DF0fF27149B47227897074653788fd23", + "commit_store": "0xF8dD2be2C6FA43e48A17146380CbEBBB4291807b", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Polygon Mainnet": { + "off_ramp": "0x8f0229804513A9Bc00c1308414AB279Dbc718ae1", + "commit_store": "0x3A85D1b8641d83a87957C6ECF1b62151213e0842", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } + }, + "ZKSync Mainnet": { + "is_native_fee_token": true, + "fee_token": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91", + "arm": "0x4e2438b1395a462E2e8D164b5f3c65d080919449", + "router": "0x748Fd769d81F5D94752bf8B0875E9301d0ba71bB", + "price_registry": "0xa0C6E00a9Fa10A04989c237dF6dfDCe2AaceE4A3", + "wrapped_native": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91", + "src_contracts": { + "Arbitrum Mainnet": { + "on_ramp": "0x9033687a0f03012e015f8f8f2a59da57531d2B43", + "deployed_at": 0 + }, + "Ethereum Mainnet": { + "on_ramp": "0x3B80Fe300c9A611abA0496e2543B66Ff7bD4B9e9", + "deployed_at": 0 + } + }, + "dest_contracts": { + "Arbitrum Mainnet": { + "off_ramp": "0xF0a08aC528668D4fe8C4cF235a8B82cbf242Fa9d", + "commit_store": "0x5a3C9b21b03E4eBcccb57D296e7ff54102F04424", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + }, + "Ethereum Mainnet": { + "off_ramp": "0x7c887B97F9Bba9355EC10e2bA949AdB491Ef44Fd", + "commit_store": "0xA42bf0c8794FA8853Ec0F1B24a489972e8CF4C30", + "receiver_dapp": "0xb509c046e1182c7b36d2d9733554bc268716803c" + } + } } + } } """ @@ -650,15 +1081,15 @@ TTL = '8h' [CCIP.Env.Network] selected_networks = [ - 'ETHEREUM_MAINNET', 'ARBITRUM_MAINNET', + 'AVALANCHE_MAINNET', + 'BSC_MAINNET', 'BASE_MAINNET', - 'WEMIX_MAINNET', + 'ETHEREUM_MAINNET', + 'KROMA_MAINNET', 'OPTIMISM_MAINNET', 'POLYGON_MAINNET', - 'AVALANCHE_MAINNET', - 'BSC_MAINNET', - 'KROMA_MAINNET' + 'WEMIX_MAINNET', ] [CCIP.Groups.load] @@ -694,7 +1125,7 @@ NetworkPairs = [ ] BiDirectionalLane = true -PhaseTimeout = '20m' +PhaseTimeout = '30m' ExistingDeployment = true [CCIP.Groups.load.TokenConfig] @@ -704,7 +1135,7 @@ NoOfTokensPerChain = 1 RequestPerUnitTime = [1] TimeUnit = '1h' TestDuration = '5h' -TestRunName = 'mainnet-2.7-ccip1.2' +TestRunName = 'Soak_test_mainnet' FailOnFirstErrorInLoad = true SkipRequestIfAnotherRequestTriggeredWithin = '40m' @@ -718,7 +1149,7 @@ AmountPerToken = 1 [CCIP.Groups.smoke] # these are all the valid network pairs NetworkPairs = [ - 'ETHEREUM_MAINNET,OPTIMISM_MAINNET', + 'ETHEREUM_MAINNET,OPTIMISM_MAINNET', 'ETHEREUM_MAINNET,AVALANCHE_MAINNET', 'ETHEREUM_MAINNET,POLYGON_MAINNET', 'ETHEREUM_MAINNET,BSC_MAINNET', From ac094f7201d68ec2612990dc89054255dc2b4cf3 Mon Sep 17 00:00:00 2001 From: Lukasz <120112546+lukaszcl@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:34:29 +0200 Subject: [PATCH 04/20] Add default test config for Grafana (#14475) * Add default test config for Grafana * Use E2E_TEST_GRAFANA_BASE_URL_GAP * Update * Bump ctf * debug - fail test * Fix --- .github/workflows/run-e2e-tests-reusable-workflow.yml | 6 ++---- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- integration-tests/testconfig/default.toml | 5 +++++ 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/run-e2e-tests-reusable-workflow.yml b/.github/workflows/run-e2e-tests-reusable-workflow.yml index f32d541c3d2..6eaa3f27988 100644 --- a/.github/workflows/run-e2e-tests-reusable-workflow.yml +++ b/.github/workflows/run-e2e-tests-reusable-workflow.yml @@ -572,8 +572,7 @@ jobs: 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: ${{ matrix.tests.test_env_vars.E2E_TEST_GRAFANA_DASHBOARD_URL || '/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs' }} + E2E_TEST_GRAFANA_DASHBOARD_URL: ${{ matrix.tests.test_env_vars.E2E_TEST_GRAFANA_DASHBOARD_URL }} 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 || '' }} @@ -788,8 +787,7 @@ jobs: 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: ${{ matrix.tests.test_env_vars.E2E_TEST_GRAFANA_DASHBOARD_URL || '/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs' }} + E2E_TEST_GRAFANA_DASHBOARD_URL: ${{ matrix.tests.test_env_vars.E2E_TEST_GRAFANA_DASHBOARD_URL }} 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 || '' }} diff --git a/integration-tests/go.mod b/integration-tests/go.mod index f8317db1bd1..c8304390a00 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -41,7 +41,7 @@ require ( github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612 github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.0 - github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.5 + github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.6 github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.1 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.0 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index f5ad0d35cc0..20a28e1dfbe 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1439,8 +1439,8 @@ github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.202409 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240911194142-506bc469d8ae/go.mod h1:ec/a20UZ7YRK4oxJcnTBFzp1+DBcJcwqEaerUMsktMs= github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.0 h1:mgjBQIEy+3V3G6K8e+6by3xndgsXdYYsdy+7kzQZwSk= github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.0/go.mod h1:pdIxrooP5CFGmC0p5NTOBiZAFtMw+5pTT4de5GY3ywA= -github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.5 h1:Owb1MQZn0NZHwtZAnPZE6TVoTx6xLrfPaUdeOYswE9M= -github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.5/go.mod h1:hS4yNF94C1lkS9gvtFXW8Km8K9NzGeR20aNfkqo5qbE= +github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.6 h1:Pzr5VAMdI2CjFftodGkilMTFlIjCHJ7oqWAD7aZvFeI= +github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.6/go.mod h1:7R5wGWWJi0dr5Y5cXbLQ4vSeIj0ElvhBaymcfvqqUmo= github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0 h1:VIxK8u0Jd0Q/VuhmsNm6Bls6Tb31H/sA3A/rbc5hnhg= github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0/go.mod h1:lyAu+oMXdNUzEDScj2DXB2IueY+SDXPPfyl/kb63tMM= github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.1 h1:2OxnPfvjC+zs0ZokSsRTRnJrEGJ4NVJwZgfroS1lPHs= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 8ebb5638303..67d2bb65095 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -16,7 +16,7 @@ require ( github.com/rs/zerolog v1.33.0 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 - github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.5 + github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.6 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.1 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.0 github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20240214231432-4ad5eb95178c diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index b3a8d086723..0954d5afd70 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1413,8 +1413,8 @@ github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.202409 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240911194142-506bc469d8ae/go.mod h1:ec/a20UZ7YRK4oxJcnTBFzp1+DBcJcwqEaerUMsktMs= github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.0 h1:mgjBQIEy+3V3G6K8e+6by3xndgsXdYYsdy+7kzQZwSk= github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.0/go.mod h1:pdIxrooP5CFGmC0p5NTOBiZAFtMw+5pTT4de5GY3ywA= -github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.5 h1:Owb1MQZn0NZHwtZAnPZE6TVoTx6xLrfPaUdeOYswE9M= -github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.5/go.mod h1:hS4yNF94C1lkS9gvtFXW8Km8K9NzGeR20aNfkqo5qbE= +github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.6 h1:Pzr5VAMdI2CjFftodGkilMTFlIjCHJ7oqWAD7aZvFeI= +github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.6/go.mod h1:7R5wGWWJi0dr5Y5cXbLQ4vSeIj0ElvhBaymcfvqqUmo= github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0 h1:VIxK8u0Jd0Q/VuhmsNm6Bls6Tb31H/sA3A/rbc5hnhg= github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0/go.mod h1:lyAu+oMXdNUzEDScj2DXB2IueY+SDXPPfyl/kb63tMM= github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.1 h1:2OxnPfvjC+zs0ZokSsRTRnJrEGJ4NVJwZgfroS1lPHs= diff --git a/integration-tests/testconfig/default.toml b/integration-tests/testconfig/default.toml index 5ce1f2b3f6b..f147d64be36 100644 --- a/integration-tests/testconfig/default.toml +++ b/integration-tests/testconfig/default.toml @@ -2,6 +2,11 @@ # 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.Grafana] +base_url="https://grafana.ops.prod.cldev.sh" +base_url_github_ci="http://localhost:8080/primary" +dashboard_url="/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + [Logging.LogStream] # supported targets: file, loki, in-memory. if empty no logs will be persisted log_targets = ["file"] From ef5b9a7407d63b3550137acd91ac333875fcafe1 Mon Sep 17 00:00:00 2001 From: Lee Yik Jiun Date: Thu, 19 Sep 2024 20:22:02 +0800 Subject: [PATCH 05/20] vrf: add soneium config for integration tests (#14443) * vrf: add soneium config for integration tests * update keyhash * update configs --- integration-tests/testconfig/default.toml | 10 ++ .../soneium_sepolia_new_env_test_config.toml | 8 ++ .../soneium_sepolia_staging_test_config.toml | 20 ++++ .../testconfig/vrfv2plus/vrfv2plus.toml | 95 +++++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 integration-tests/testconfig/vrfv2plus/overrides/new_env/soneium_sepolia_new_env_test_config.toml create mode 100644 integration-tests/testconfig/vrfv2plus/overrides/staging/soneium_sepolia_staging_test_config.toml diff --git a/integration-tests/testconfig/default.toml b/integration-tests/testconfig/default.toml index f147d64be36..1d84b1d0282 100644 --- a/integration-tests/testconfig/default.toml +++ b/integration-tests/testconfig/default.toml @@ -722,3 +722,13 @@ gas_tip_cap = 30_000_000_000 gas_price_estimation_enabled = true gas_price_estimation_blocks = 500 gas_price_estimation_tx_priority = "standard" + +#### + +[Network.EVMNetworks.SONEIUM_SEPOLIA] +evm_name = "SONEIUM_SEPOLIA" +evm_chain_id = 1946 +client_implementation = "Optimism" +evm_simulated = false + +#### \ No newline at end of file diff --git a/integration-tests/testconfig/vrfv2plus/overrides/new_env/soneium_sepolia_new_env_test_config.toml b/integration-tests/testconfig/vrfv2plus/overrides/new_env/soneium_sepolia_new_env_test_config.toml new file mode 100644 index 00000000000..beacf9c5f7c --- /dev/null +++ b/integration-tests/testconfig/vrfv2plus/overrides/new_env/soneium_sepolia_new_env_test_config.toml @@ -0,0 +1,8 @@ +[Network] +selected_networks = ["SONEIUM_SEPOLIA"] + +[SONEIUM_SEPOLIA.VRFv2Plus.General] +use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2plus/overrides/staging/soneium_sepolia_staging_test_config.toml b/integration-tests/testconfig/vrfv2plus/overrides/staging/soneium_sepolia_staging_test_config.toml new file mode 100644 index 00000000000..df973d87022 --- /dev/null +++ b/integration-tests/testconfig/vrfv2plus/overrides/staging/soneium_sepolia_staging_test_config.toml @@ -0,0 +1,20 @@ +[Network] +selected_networks = ["SONEIUM_SEPOLIA"] + +[SONEIUM_SEPOLIA.VRFv2Plus.General] +use_existing_env = true + +[SONEIUM_SEPOLIA.VRFv2Plus.ExistingEnv] +coordinator_address = "0x81e211D679231615C2601E82B658Bde449AF240f" +consumer_address = "" +use_existing_wrapper = true +wrapper_address = "0xD06CfcDAa6f32BB131e693F99f502ac31588CBC8" +sub_id = "" +key_hash = "0x9552c9542c079db4f8c6867e27f6c4780e3e24d895cb0890ca9984764dbe7200" +create_fund_subs_and_add_consumers = true +node_sending_key_funding_min = 1 +node_sending_keys = [ + "0x22643FcF2018ac636477CFE19Ed17071FF7A5cA0", + # BHS + "0xD012B272E8ec6eA7A3373E340Ead52FA2C7352ea", +] diff --git a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml index c2b0bcfc003..c9f5ac12a81 100644 --- a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml +++ b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml @@ -822,6 +822,101 @@ rate_limit_unit_duration = "1m" rps = 1 +### SONEIUM SEPOLIA Config +[SONEIUM_SEPOLIA.Common] +chainlink_node_funding = 5 +[SONEIUM_SEPOLIA.VRFv2Plus.General] +use_test_coordinator = false +#todo - need to have separate minimum_confirmations config for Coordinator, CL Node and Consumer request +minimum_confirmations = 0 + +# Consumer Request config +subscription_billing_type = "LINK_AND_NATIVE" +callback_gas_limit = 1000000 + +# NEW ENV CONFIG +# CL Node config +cl_node_max_gas_price_gwei = 30 +number_of_sending_keys_to_create = 0 + +# Coordinator config +max_gas_limit_coordinator_config = 2500000 +fallback_wei_per_unit_link = "4619667900000000" +staleness_seconds = 172_800 +gas_after_payment_calculation = 42_500 +fulfillment_flat_fee_native_ppm = 0 +fulfillment_flat_fee_link_discount_ppm = 0 +native_premium_percentage = 60 +link_premium_percentage = 50 + +# Wrapper config +wrapped_gas_overhead = 13_400 +coordinator_gas_overhead_native = 128_500 +coordinator_gas_overhead_link = 150_400 +coordinator_gas_overhead_per_word = 435 +coordinator_native_premium_percentage = 60 +coordinator_link_premium_percentage = 50 +wrapper_max_number_of_words = 10 + +# VRF Job config +vrf_job_forwarding_allowed = false +vrf_job_estimate_gas_multiplier = 1.15 +vrf_job_batch_fulfillment_enabled = true +vrf_job_batch_fulfillment_gas_multiplier = 1.1 +vrf_job_poll_period = "2s" +vrf_job_request_timeout = "2h0m0s" +vrf_job_simulation_block = "pending" + +# BHS Job config +bhs_job_wait_blocks = 30 +bhs_job_lookback_blocks = 200 +bhs_job_poll_period = "2s" +bhs_job_run_timeout = "30s" +# NEW ENV CONFIG END + +#SMOKE TEST CONFIG +[SONEIUM_SEPOLIA-Smoke.VRFv2Plus.General] +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 3 +subscription_funding_amount_native = 1 +subscription_refunding_amount_link = 3 +subscription_refunding_amount_native = 1 +number_of_words = 1 +random_words_fulfilled_event_timeout = "1m30s" +wait_for_256_blocks_timeout = "10m" + +wrapper_consumer_funding_amount_native_token = 1.0 +wrapper_consumer_funding_amount_link = 5 + +[SONEIUM_SEPOLIA-Soak.VRFv2Plus.General] +randomness_request_count_per_request = 4 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +number_of_sending_keys_to_create = 0 +subscription_funding_amount_link = 500 +subscription_funding_amount_native = 100 + +[SONEIUM_SEPOLIA-Soak.VRFv2Plus.Performance] +test_duration = "2h" +rate_limit_unit_duration = "10s" +rps = 1 + +[SONEIUM_SEPOLIA-Stress.VRFv2Plus.General] +randomness_request_count_per_request = 60 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +number_of_sending_keys_to_create = 0 +subscription_funding_amount_link = 500 +subscription_funding_amount_native=100 + +[SONEIUM_SEPOLIA-Stress.VRFv2Plus.Performance] +test_duration = "10m" +rate_limit_unit_duration = "1m" +rps = 1 + + ### ETH SEPOLIA Config [SEPOLIA.VRFv2Plus.General] use_test_coordinator = true From 66bced952460e30930f03a7f577150754dffdd1c Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Thu, 19 Sep 2024 07:36:54 -0500 Subject: [PATCH 06/20] core/config/toml: include value in InsecureConnection error message (#14495) --- core/config/toml/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/config/toml/types.go b/core/config/toml/types.go index 2eb66d10a9f..497e33d5ddd 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -1695,7 +1695,7 @@ func (b *Telemetry) ValidateConfig() (err error) { } if b.InsecureConnection != nil && *b.InsecureConnection { if build.IsProd() { - err = multierr.Append(err, configutils.ErrInvalid{Name: "InsecureConnection", Msg: "cannot be used in production builds"}) + err = multierr.Append(err, configutils.ErrInvalid{Name: "InsecureConnection", Value: true, Msg: "cannot be used in production builds"}) } } else { if b.CACertFile == nil || *b.CACertFile == "" { From 7ffbfbf948a4c64d4b0c9bc295804654c2235f33 Mon Sep 17 00:00:00 2001 From: Anindita Ghosh <88458927+AnieeG@users.noreply.github.com> Date: Thu, 19 Sep 2024 08:21:26 -0700 Subject: [PATCH 07/20] CCIP-3428 Enabling ccip smoke test for testnet (#14452) * enabling test for testnet * home chain selector logic * testnet deployment * remove unwanted * lint fix * add readme * fix typo * fix * make timer rely on test deadline * update comment * update comment --- integration-tests/actions/actions.go | 7 +- integration-tests/actions/refund.go | 8 + .../ccip-tests/testsetups/test_env.go | 3 + .../contracts/contract_models.go | 6 +- integration-tests/deployment/README.md | 6 +- .../deployment/ccip/add_chain_test.go | 3 +- .../deployment/ccip/add_lane_test.go | 3 +- .../ccip/changeset/2_initial_deploy_test.go | 3 +- .../deployment/ccip/test_assertions.go | 14 +- .../deployment/ccip/test_helpers.go | 25 +-- .../deployment/devenv/.sample.env | 22 ++- integration-tests/deployment/devenv/README.md | 45 +++++ .../deployment/devenv/build_env.go | 185 +++++++++++++++--- integration-tests/deployment/devenv/chain.go | 60 ++---- integration-tests/deployment/devenv/don.go | 78 ++++---- .../deployment/devenv/environment.go | 7 +- integration-tests/deployment/environment.go | 5 +- .../deployment/memory/environment.go | 3 - .../docker/test_env/test_env_builder.go | 39 ++-- integration-tests/smoke/ccip_test.go | 3 +- integration-tests/testconfig/ccip/ccip.toml | 6 + integration-tests/testconfig/ccip/config.go | 7 + .../ccip/overrides/sepolia_avax_binance.toml | 55 ++++++ 23 files changed, 426 insertions(+), 167 deletions(-) create mode 100644 integration-tests/deployment/devenv/README.md create mode 100644 integration-tests/testconfig/ccip/overrides/sepolia_avax_binance.toml diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index c420f8e6729..198fa8e0dc8 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -25,6 +25,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/logging" "github.com/smartcontractkit/chainlink-testing-framework/lib/testreporters" "github.com/smartcontractkit/chainlink-testing-framework/lib/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" @@ -285,7 +286,7 @@ func fundChainlinkNodesAtAnyKey( return err } - fromAddress, err := privateKeyToAddress(privateKey) + fromAddress, err := PrivateKeyToAddress(privateKey) if err != nil { return err } @@ -336,7 +337,7 @@ type FundsToSendPayload struct { // to given address. You can override any or none of the following: gas limit, gas price, gas fee cap, gas tip cap. // Values that are not set will be estimated or taken from config. func SendFunds(logger zerolog.Logger, client *seth.Client, payload FundsToSendPayload) (*types.Receipt, error) { - fromAddress, err := privateKeyToAddress(payload.PrivateKey) + fromAddress, err := PrivateKeyToAddress(payload.PrivateKey) if err != nil { return nil, err } @@ -910,7 +911,7 @@ func deployAnyOCRv1Contracts( return ocrInstances, nil } -func privateKeyToAddress(privateKey *ecdsa.PrivateKey) (common.Address, error) { +func PrivateKeyToAddress(privateKey *ecdsa.PrivateKey) (common.Address, error) { publicKey := privateKey.Public() publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) if !ok { diff --git a/integration-tests/actions/refund.go b/integration-tests/actions/refund.go index 1835d9a04a4..bcdf6a380d8 100644 --- a/integration-tests/actions/refund.go +++ b/integration-tests/actions/refund.go @@ -234,6 +234,14 @@ func (r *OvershotTransferRetrier) Retry(ctx context.Context, logger zerolog.Logg // of strategies to attempt to return funds, including retrying with less funds if the transaction fails due to // insufficient funds, and retrying with a higher gas limit if the transaction fails due to gas too low. func ReturnFundsFromNodes(log zerolog.Logger, client *seth.Client, chainlinkNodes []contracts.ChainlinkNodeWithKeysAndAddress) error { + var keyExporters []contracts.ChainlinkKeyExporter + for _, node := range chainlinkNodes { + keyExporters = append(keyExporters, node) + } + return ReturnFundsFromKeyExporterNodes(log, client, keyExporters) +} + +func ReturnFundsFromKeyExporterNodes(log zerolog.Logger, client *seth.Client, chainlinkNodes []contracts.ChainlinkKeyExporter) error { if client == nil { return fmt.Errorf("seth client is nil, unable to return funds from chainlink nodes") } diff --git a/integration-tests/ccip-tests/testsetups/test_env.go b/integration-tests/ccip-tests/testsetups/test_env.go index 4d968e83315..263d291453d 100644 --- a/integration-tests/ccip-tests/testsetups/test_env.go +++ b/integration-tests/ccip-tests/testsetups/test_env.go @@ -332,6 +332,9 @@ func DeployLocalCluster( // a func to start the CL nodes asynchronously deployCL := func() error { noOfNodes := pointer.GetInt(testInputs.EnvInput.NewCLCluster.NoOfNodes) + if env.ClCluster == nil { + env.ClCluster = &test_env.ClCluster{} + } // 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 { diff --git a/integration-tests/contracts/contract_models.go b/integration-tests/contracts/contract_models.go index 46f10f06bb0..006ee5db6a8 100644 --- a/integration-tests/contracts/contract_models.go +++ b/integration-tests/contracts/contract_models.go @@ -151,9 +151,13 @@ type OffchainAggregatorData struct { type ChainlinkNodeWithKeysAndAddress interface { MustReadOCRKeys() (*client.OCRKeys, error) MustReadP2PKeys() (*client.P2PKeys, error) - ExportEVMKeysForChain(string) ([]*client.ExportedEVMKey, error) PrimaryEthAddress() (string, error) EthAddresses() ([]string, error) + ChainlinkKeyExporter +} + +type ChainlinkKeyExporter interface { + ExportEVMKeysForChain(string) ([]*client.ExportedEVMKey, error) } type ChainlinkNodeWithForwarder interface { diff --git a/integration-tests/deployment/README.md b/integration-tests/deployment/README.md index 1c2019b540b..000219c8aba 100644 --- a/integration-tests/deployment/README.md +++ b/integration-tests/deployment/README.md @@ -19,11 +19,11 @@ environments like testnet/mainnet. - In-memory environment for fast integration testing - EVM only -/deployment/docker +/deployment/devenv - Coming soon -- package name `docker` +- package name `devenv` - Docker environment for higher fidelity testing -- Support non-EVMs +- Support non-EVMs (yet to be implemented) /deployment/ccip - package name `ccipdeployment` diff --git a/integration-tests/deployment/ccip/add_chain_test.go b/integration-tests/deployment/ccip/add_chain_test.go index fdfbb6e69a6..9441f1a2da6 100644 --- a/integration-tests/deployment/ccip/add_chain_test.go +++ b/integration-tests/deployment/ccip/add_chain_test.go @@ -154,8 +154,9 @@ func TestAddChainInbound(t *testing.T) { // TODO: Send via all inbound lanes and use parallel helper // Now that the proposal has been executed we expect to be able to send traffic to this new 4th chain. - startBlock, err := e.Env.Chains[newChain].LatestBlockNum(testcontext.Get(t)) + latesthdr, err := e.Env.Chains[newChain].Client.HeaderByNumber(testcontext.Get(t), nil) require.NoError(t, err) + startBlock := latesthdr.Number.Uint64() seqNr := SendRequest(t, e.Env, state, initialDeploy[0], newChain, true) require.NoError(t, ConfirmExecWithSeqNr(t, e.Env.Chains[initialDeploy[0]], e.Env.Chains[newChain], state.Chains[newChain].OffRamp, &startBlock, seqNr)) diff --git a/integration-tests/deployment/ccip/add_lane_test.go b/integration-tests/deployment/ccip/add_lane_test.go index 63af3b69c45..d43526d8d49 100644 --- a/integration-tests/deployment/ccip/add_lane_test.go +++ b/integration-tests/deployment/ccip/add_lane_test.go @@ -50,8 +50,9 @@ func TestAddLane(t *testing.T) { require.Len(t, offRamps, 0) } } - startBlock, err := e.Env.Chains[to].LatestBlockNum(testcontext.Get(t)) + latesthdr, err := e.Env.Chains[to].Client.HeaderByNumber(testcontext.Get(t), nil) require.NoError(t, err) + startBlock := latesthdr.Number.Uint64() seqNum := SendRequest(t, e.Env, state, from, to, false) require.Equal(t, uint64(1), seqNum) require.NoError(t, ConfirmExecWithSeqNr(t, e.Env.Chains[from], e.Env.Chains[to], state.Chains[to].OffRamp, &startBlock, seqNum)) diff --git a/integration-tests/deployment/ccip/changeset/2_initial_deploy_test.go b/integration-tests/deployment/ccip/changeset/2_initial_deploy_test.go index 8de2c4617b4..90a8627f38d 100644 --- a/integration-tests/deployment/ccip/changeset/2_initial_deploy_test.go +++ b/integration-tests/deployment/ccip/changeset/2_initial_deploy_test.go @@ -62,8 +62,9 @@ func Test0002_InitialDeploy(t *testing.T) { if src == dest { continue } - block, err := destChain.LatestBlockNum(testcontext.Get(t)) + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) require.NoError(t, err) + block := latesthdr.Number.Uint64() startBlocks[dest] = &block seqNum := ccipdeployment.SendRequest(t, e, state, src, dest, false) expectedSeqNum[dest] = seqNum diff --git a/integration-tests/deployment/ccip/test_assertions.go b/integration-tests/deployment/ccip/test_assertions.go index 2041c1a9779..02a10fff3e6 100644 --- a/integration-tests/deployment/ccip/test_assertions.go +++ b/integration-tests/deployment/ccip/test_assertions.go @@ -78,7 +78,15 @@ func ConfirmCommitWithExpectedSeqNumRange( } defer subscription.Unsubscribe() - timer := time.NewTimer(5 * time.Minute) + var duration time.Duration + deadline, ok := t.Deadline() + if ok { + // make this timer end a minute before so that we don't hit the deadline + duration = deadline.Sub(time.Now().Add(-1 * time.Minute)) + } else { + duration = 5 * time.Minute + } + timer := time.NewTimer(duration) defer timer.Stop() ticker := time.NewTicker(2 * time.Second) defer ticker.Stop() @@ -97,8 +105,8 @@ func ConfirmCommitWithExpectedSeqNumRange( case subErr := <-subscription.Err(): return fmt.Errorf("subscription error: %w", subErr) case <-timer.C: - return fmt.Errorf("timed out waiting for commit report on chain selector %d from source selector %d expected seq nr range %s", - dest.Selector, src.Selector, expectedSeqNumRange.String()) + return fmt.Errorf("timed out after waiting %s duration for commit report on chain selector %d from source selector %d expected seq nr range %s", + duration.String(), dest.Selector, src.Selector, expectedSeqNumRange.String()) case report := <-sink: if len(report.Report.MerkleRoots) > 0 { // Check the interval of sequence numbers and make sure it matches diff --git a/integration-tests/deployment/ccip/test_helpers.go b/integration-tests/deployment/ccip/test_helpers.go index 4458a49abc7..330cbae1964 100644 --- a/integration-tests/deployment/ccip/test_helpers.go +++ b/integration-tests/deployment/ccip/test_helpers.go @@ -8,6 +8,8 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/smartcontractkit/chainlink-testing-framework/lib/logging" + "github.com/ethereum/go-ethereum/common" chainsel "github.com/smartcontractkit/chain-selectors" "github.com/stretchr/testify/require" @@ -158,7 +160,9 @@ func SendRequest(t *testing.T, e deployment.Environment, state CCIPOnChainState, }, []uint64{dest}) require.NoError(t, err) require.True(t, it.Next()) - return it.Event.Message.Header.SequenceNumber + seqNum := it.Event.Message.Header.SequenceNumber + t.Logf("CCIP message sent from chain selector %d to chain selector %d tx %s seqNum %d", src, dest, tx.Hash().String(), seqNum) + return seqNum } // DeployedLocalDevEnvironment is a helper struct for setting up a local dev environment with docker @@ -179,15 +183,13 @@ func NewDeployedLocalDevEnvironment(t *testing.T, lggr logger.Logger) DeployedLo require.NotEmpty(t, envConfig.JDConfig, "jdUrl should not be empty") chains, err := devenv.NewChains(lggr, envConfig.Chains) require.NoError(t, err) - homeChainSel := uint64(0) - homeChainEVM := uint64(0) + // locate the home chain + homeChainSel := envConfig.HomeChainSelector + require.NotEmpty(t, homeChainSel, "homeChainSel should not be empty") + homeChainEVM, err := chainsel.ChainIdFromSelector(homeChainSel) + require.NoError(t, err) + require.NotEmpty(t, homeChainEVM, "homeChainEVM should not be empty") - // Say first chain is home chain. - for chainSel := range chains { - homeChainEVM, _ = chainsel.ChainIdFromSelector(chainSel) - homeChainSel = chainSel - break - } // deploy the capability registry ab, capReg, err := DeployCapReg(lggr, chains, homeChainSel) require.NoError(t, err) @@ -205,10 +207,9 @@ func NewDeployedLocalDevEnvironment(t *testing.T, lggr logger.Logger) DeployedLo require.NoError(t, err) require.NotNil(t, e) require.NotNil(t, don) - + zeroLogLggr := logging.GetTestLogger(t) // fund the nodes - require.NoError(t, don.FundNodes(ctx, deployment.E18Mult(10), e.Chains)) - + devenv.FundNodes(t, zeroLogLggr, testEnv, cfg, don.PluginNodes()) return DeployedLocalDevEnvironment{ Ab: ab, Env: *e, diff --git a/integration-tests/deployment/devenv/.sample.env b/integration-tests/deployment/devenv/.sample.env index 97d550079a9..f0505cf857a 100644 --- a/integration-tests/deployment/devenv/.sample.env +++ b/integration-tests/deployment/devenv/.sample.env @@ -2,4 +2,24 @@ E2E_JD_IMAGE= E2E_JD_VERSION= E2E_TEST_CHAINLINK_IMAGE=public.ecr.aws/w0i8p0z9/chainlink-ccip -E2E_TEST_CHAINLINK_VERSION=2.14.0-ccip1.5.0 \ No newline at end of file +E2E_TEST_CHAINLINK_VERSION=2.14.0-ccip1.5.0 + +# RPC Configuration +E2E_TEST_SEPOLIA_WALLET_KEY= +E2E_TEST_SEPOLIA_RPC_HTTP_URL_1= +E2E_TEST_SEPOLIA_RPC_HTTP_URL_2= +E2E_TEST_SEPOLIA_RPC_WS_URL_1= +E2E_TEST_SEPOLIA_RPC_WS_URL_2= + +E2E_TEST_AVALANCHE_FUJI_WALLET_KEY= +E2E_TEST_AVALANCHE_FUJI_RPC_HTTP_URL_1= +E2E_TEST_AVALANCHE_FUJI_RPC_HTTP_URL_2= +E2E_TEST_AVALANCHE_FUJI_RPC_WS_URL_1= +E2E_TEST_AVALANCHE_FUJI_RPC_WS_URL_2= + +E2E_TEST_BSC_TESTNET_WALLET_KEY= +E2E_TEST_BSC_TESTNET_RPC_HTTP_URL_1= +E2E_TEST_BSC_TESTNET_RPC_HTTP_URL_2= +E2E_TEST_BSC_TESTNET_RPC_WS_URL_1= +E2E_TEST_BSC_TESTNET_RPC_WS_URL_2= + diff --git a/integration-tests/deployment/devenv/README.md b/integration-tests/deployment/devenv/README.md new file mode 100644 index 00000000000..a1f264dfce2 --- /dev/null +++ b/integration-tests/deployment/devenv/README.md @@ -0,0 +1,45 @@ +## Overview + +This package is used to create ephemeral environment for local/CI testing. +It sets up an environment with local Docker containers running Chainlink nodes and a job distributor. +It can either create new simulated private Ethereum network containers or connect to existing testnets/mainnets. + +### Run Tests with Devenv + +The tests created with this environment are run as [end-to-end integration smoke tests](../../smoke). + +#### Setting Up Testconfig with Simulated Private Ethereum Network + +To run tests (e.g., [ccip-test](../../smoke/ccip_test.go)), +you need to set up the testconfig following the [testconfig setup instructions](../../testconfig/README.md). +The testconfig specifies the details of the different configurations to set up the environment and run the tests. +Generally, tests are run with the [default](../../testconfig/default.toml) config unless overridden by product-specific config. +For example, the [ccip-test](../../smoke/ccip_test.go) uses [ccip.toml](../../testconfig/ccip/ccip.toml) to specify +CCIP-specific test environment details. + +There are additional secret configuration parameters required by the `devenv` environment that are not stored in the testconfig. +These are read from environment variables. For example, Chainlink image, Job-Distributor image, etc. +All such environment variables are listed in the [sample.env](./.sample.env) file. +You can create a `.env` file in the same directory of the test and set the required environment variables. + +#### Setting Up Testconfig for Running Tests with Existing Testnet/Mainnet + +To run tests with existing testnet/mainnet, set up the testconfig with the details of the testnet/mainnet networks. +Following the integration-test [testconfig framework](../../testconfig/README.md#configuration-and-overrides), +create a new `overrides.toml` file with testnet/mainnet network details and place it under any location in the `integration-tests` directory. +By default, tests are run with private Ethereum network containers set up in the same Docker network as +the Chainlink nodes and job distributor. To run tests against existing testnet/mainnet, +set the `selected_network` field in the testconfig with the specific network names. + +For example, if running [ccip-smoke](../../smoke/ccip_test.go) tests with Sepolia, Avax, and Binance testnets, +copy the contents of [sepolia_avax_binance.toml](../../testconfig/ccip/overrides/sepolia_avax_binance.toml) +to the `overrides.toml` file. + +Before running the test, ensure that RPC and wallet secrets are set as environment variables. +Refer to the environment variables pattern in the [sample.env](./.sample.env) file to +provide necessary secrets applicable to the network you are running the tests against: +- `E2E_TEST__WALLET_KEY_` +- `E2E_TEST__RPC_HTTP_URL_` +- `E2E_TEST__RPC_WS_URL_` + +Now you are all set to run the tests with the existing testnet/mainnet. \ No newline at end of file diff --git a/integration-tests/deployment/devenv/build_env.go b/integration-tests/deployment/devenv/build_env.go index 0373cf0b214..61e677ca435 100644 --- a/integration-tests/deployment/devenv/build_env.go +++ b/integration-tests/deployment/devenv/build_env.go @@ -9,22 +9,30 @@ import ( "github.com/AlekSi/pointer" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/rs/zerolog" chainselectors "github.com/smartcontractkit/chain-selectors" "github.com/stretchr/testify/require" "github.com/subosito/gotenv" + "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/conversions" + "github.com/smartcontractkit/chainlink-testing-framework/seth" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/lib/config" ctftestenv "github.com/smartcontractkit/chainlink-testing-framework/lib/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/lib/docker/test_env/job_distributor" "github.com/smartcontractkit/chainlink-testing-framework/lib/networks" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/ptr" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups" clclient "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/deployment" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink/integration-tests/utils" "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) @@ -43,18 +51,31 @@ func CreateDockerEnv(t *testing.T) ( cfg, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.CCIP) require.NoError(t, err, "Error getting config") + evmNetworks := networks.MustGetSelectedNetworkConfig(cfg.GetNetworkConfig()) + + // find out if the selected networks are provided with PrivateEthereumNetworks configs + // if yes, PrivateEthereumNetworkConfig will be used to create simulated private ethereum networks in docker environment var privateEthereumNetworks []*ctf_config.EthereumNetworkConfig - for _, network := range cfg.CCIP.PrivateEthereumNetworks { - privateEthereumNetworks = append(privateEthereumNetworks, network) + for _, name := range cfg.GetNetworkConfig().SelectedNetworks { + if network, exists := cfg.CCIP.PrivateEthereumNetworks[name]; exists { + privateEthereumNetworks = append(privateEthereumNetworks, network) + } } - env, err := test_env.NewCLTestEnvBuilder(). + + builder := test_env.NewCLTestEnvBuilder(). WithTestConfig(&cfg). WithTestInstance(t). - WithPrivateEthereumNetworks(privateEthereumNetworks). - WithStandardCleanup(). - Build() + WithStandardCleanup() + + // if private ethereum networks are provided, we will use them to create the test environment + // otherwise we will use the network URLs provided in the network config + if len(privateEthereumNetworks) > 0 { + builder = builder.WithPrivateEthereumNetworks(privateEthereumNetworks) + } + env, err := builder.Build() require.NoError(t, err, "Error building test environment") - chains := CreateChainConfigFromPrivateEthereumNetworks(t, env, cfg.CCIP.PrivateEthereumNetworks, cfg.GetNetworkConfig()) + + chains := CreateChainConfigFromNetworks(t, env, privateEthereumNetworks, cfg.GetNetworkConfig()) var jdConfig JDConfig // TODO : move this as a part of test_env setup with an input in testconfig @@ -89,9 +110,24 @@ func CreateDockerEnv(t *testing.T) ( } require.NotEmpty(t, jdConfig, "JD config is empty") + homeChainSelector, err := cfg.CCIP.GetHomeChainSelector() + require.NoError(t, err, "Error getting home chain selector") + homeChainID, err := chainselectors.ChainIdFromSelector(homeChainSelector) + require.NoError(t, err, "Error getting chain id from selector") + // verify if the home chain selector is valid + validHomeChain := false + for _, net := range evmNetworks { + if net.ChainID == int64(homeChainID) { + validHomeChain = true + break + } + } + require.True(t, validHomeChain, "Invalid home chain selector, chain not found in network config") + return &EnvironmentConfig{ - Chains: chains, - JDConfig: jdConfig, + Chains: chains, + JDConfig: jdConfig, + HomeChainSelector: homeChainSelector, }, env, cfg } @@ -107,12 +143,19 @@ func StartChainlinkNodes( ) error { evmNetworks := networks.MustGetSelectedNetworkConfig(cfg.GetNetworkConfig()) for i, net := range evmNetworks { - rpcProvider, err := env.GetRpcProvider(net.ChainID) - require.NoError(t, err, "Error getting rpc provider") - evmNetworks[i].HTTPURLs = rpcProvider.PrivateHttpUrls() - evmNetworks[i].URLs = rpcProvider.PrivateWsUrsl() + // if network is simulated, update the URLs with private chain RPCs in the docker test environment + // so that nodes can internally connect to the chain + if net.Simulated { + rpcProvider, err := env.GetRpcProvider(net.ChainID) + require.NoError(t, err, "Error getting rpc provider") + evmNetworks[i].HTTPURLs = rpcProvider.PrivateHttpUrls() + evmNetworks[i].URLs = rpcProvider.PrivateWsUrsl() + } } noOfNodes := pointer.GetInt(cfg.CCIP.CLNode.NoOfPluginNodes) + pointer.GetInt(cfg.CCIP.CLNode.NoOfBootstraps) + if env.ClCluster == nil { + env.ClCluster = &test_env.ClCluster{} + } var nodeInfo []NodeInfo for i := 1; i <= noOfNodes; i++ { if i <= pointer.GetInt(cfg.CCIP.CLNode.NoOfBootstraps) { @@ -172,17 +215,88 @@ func StartChainlinkNodes( InternalIP: n.API.InternalIP(), } } - envConfig.nodeInfo = nodeInfo return nil } -// CreateChainConfigFromPrivateEthereumNetworks creates a list of ChainConfig from the private ethereum networks created by the test environment. +// FundNodes sends funds to the chainlink nodes based on the provided test config +// It also sets up a clean-up function to return the funds back to the deployer account once the test is done +// It assumes that the chainlink nodes are already started and the account addresses for all chains are available +func FundNodes(t *testing.T, lggr zerolog.Logger, env *test_env.CLClusterTestEnv, cfg tc.TestConfig, nodes []Node) { + evmNetworks := networks.MustGetSelectedNetworkConfig(cfg.GetNetworkConfig()) + for i, net := range evmNetworks { + // if network is simulated, update the URLs with deployed chain RPCs in the docker test environment + if net.Simulated { + rpcProvider, err := env.GetRpcProvider(net.ChainID) + require.NoError(t, err, "Error getting rpc provider") + evmNetworks[i].HTTPURLs = rpcProvider.PublicHttpUrls() + evmNetworks[i].URLs = rpcProvider.PublicWsUrls() + } + } + t.Cleanup(func() { + for i := range evmNetworks { + // if simulated no need for balance return + if evmNetworks[i].Simulated { + continue + } + evmNetwork := evmNetworks[i] + sethClient, err := utils.TestAwareSethClient(t, cfg, &evmNetwork) + require.NoError(t, err, "Error getting seth client for network %s", evmNetwork.Name) + require.Greater(t, len(sethClient.PrivateKeys), 0, seth.ErrNoKeyLoaded) + var keyExporters []contracts.ChainlinkKeyExporter + for j := range nodes { + node := nodes[j] + keyExporters = append(keyExporters, &node) + } + if err := actions.ReturnFundsFromKeyExporterNodes(lggr, sethClient, keyExporters); err != nil { + lggr.Error().Err(err).Str("Network", evmNetwork.Name). + Msg("Error attempting to return funds from chainlink nodes to network's default wallet. " + + "Environment is left running so you can try manually!") + } + } + }) + for i := range evmNetworks { + evmNetwork := evmNetworks[i] + sethClient, err := utils.TestAwareSethClient(t, cfg, &evmNetwork) + require.NoError(t, err, "Error getting seth client for network %s", evmNetwork.Name) + require.Greater(t, len(sethClient.PrivateKeys), 0, seth.ErrNoKeyLoaded) + privateKey := sethClient.PrivateKeys[0] + for _, node := range nodes { + nodeAddr, ok := node.AccountAddr[uint64(evmNetwork.ChainID)] + require.True(t, ok, "Account address not found for chain %d", evmNetwork.ChainID) + fromAddress, err := actions.PrivateKeyToAddress(privateKey) + require.NoError(t, err, "Error getting address from private key") + amount := big.NewFloat(pointer.GetFloat64(cfg.Common.ChainlinkNodeFunding)) + toAddr := common.HexToAddress(nodeAddr) + receipt, err := actions.SendFunds(lggr, sethClient, actions.FundsToSendPayload{ + ToAddress: toAddr, + Amount: conversions.EtherToWei(amount), + PrivateKey: privateKey, + }) + require.NoError(t, err, "Error sending funds to node %s", node.Name) + require.NotNil(t, receipt, "Receipt is nil") + txHash := "(none)" + if receipt != nil { + txHash = receipt.TxHash.String() + } + lggr.Info(). + Str("From", fromAddress.Hex()). + Str("To", toAddr.String()). + Str("TxHash", txHash). + Str("Amount", amount.String()). + Msg("Funded Chainlink node") + } + } +} + +// CreateChainConfigFromNetworks creates a list of ChainConfig from the network config provided in test config. +// It either creates it from the private ethereum networks created by the test environment or from the +// network URLs provided in the network config ( if the network is a live testnet). // It uses the private keys from the network config to create the deployer key for each chain. -func CreateChainConfigFromPrivateEthereumNetworks( +func CreateChainConfigFromNetworks( t *testing.T, env *test_env.CLClusterTestEnv, - privateEthereumNetworks map[string]*ctf_config.EthereumNetworkConfig, + privateEthereumNetworks []*ctf_config.EthereumNetworkConfig, networkConfig *ctf_config.NetworkConfig, ) []ChainConfig { evmNetworks := networks.MustGetSelectedNetworkConfig(networkConfig) @@ -192,6 +306,29 @@ func CreateChainConfigFromPrivateEthereumNetworks( networkPvtKeys[net.ChainID] = net.PrivateKeys[0] } var chains []ChainConfig + // if private ethereum networks are not provided, we will create chains from the network URLs + if len(privateEthereumNetworks) == 0 { + for _, net := range evmNetworks { + chainId := net.ChainID + chainName, err := chainselectors.NameFromChainId(uint64(chainId)) + require.NoError(t, err, "Error getting chain name") + pvtKeyStr, exists := networkPvtKeys[chainId] + require.Truef(t, exists, "Private key not found for chain id %d", chainId) + pvtKey, err := crypto.HexToECDSA(pvtKeyStr) + require.NoError(t, err) + deployer, err := bind.NewKeyedTransactorWithChainID(pvtKey, big.NewInt(chainId)) + require.NoError(t, err) + chains = append(chains, ChainConfig{ + ChainID: uint64(chainId), + ChainName: chainName, + ChainType: "EVM", + WSRPCs: net.URLs, + HTTPRPCs: net.HTTPURLs, + DeployerKey: deployer, + }) + } + return chains + } for _, networkCfg := range privateEthereumNetworks { chainId := networkCfg.EthereumChainConfig.ChainID chainName, err := chainselectors.NameFromChainId(uint64(chainId)) @@ -205,14 +342,12 @@ func CreateChainConfigFromPrivateEthereumNetworks( deployer, err := bind.NewKeyedTransactorWithChainID(pvtKey, big.NewInt(int64(chainId))) require.NoError(t, err) chains = append(chains, ChainConfig{ - ChainID: uint64(chainId), - ChainName: chainName, - ChainType: "EVM", - WSRPCs: rpcProvider.PublicWsUrls(), - HTTPRPCs: rpcProvider.PublicHttpUrls(), - PrivateHTTPRPCs: rpcProvider.PrivateHttpUrls(), - PrivateWSRPCs: rpcProvider.PrivateWsUrsl(), - DeployerKey: deployer, + ChainID: uint64(chainId), + ChainName: chainName, + ChainType: "EVM", + WSRPCs: rpcProvider.PublicWsUrls(), + HTTPRPCs: rpcProvider.PublicHttpUrls(), + DeployerKey: deployer, }) } return chains diff --git a/integration-tests/deployment/devenv/chain.go b/integration-tests/deployment/devenv/chain.go index 6374a2c213d..e40bbc066fd 100644 --- a/integration-tests/deployment/devenv/chain.go +++ b/integration-tests/deployment/devenv/chain.go @@ -3,11 +3,9 @@ package devenv import ( "context" "fmt" - "math/big" "time" "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/ethclient" "github.com/sethvargo/go-retry" @@ -20,14 +18,12 @@ import ( // ChainConfig holds the configuration for a with a deployer key which can be used to send transactions to the chain. type ChainConfig struct { - ChainID uint64 // chain id as per EIP-155, mainly applicable for EVM chains - ChainName string // name of the chain populated from chainselector repo - ChainType string // should denote the chain family. Acceptable values are EVM, COSMOS, SOLANA, STARKNET, APTOS etc - WSRPCs []string // websocket rpcs to connect to the chain - HTTPRPCs []string // http rpcs to connect to the chain - PrivateWSRPCs []string // applicable for private chains spun up with docker/K8s only so that nodes within same cluster can connect internally - PrivateHTTPRPCs []string // applicable for private chains spun up with docker/K8s only so that nodes within same cluster can connect internally - DeployerKey *bind.TransactOpts // key to send transactions to the chain + ChainID uint64 // chain id as per EIP-155, mainly applicable for EVM chains + ChainName string // name of the chain populated from chainselector repo + ChainType string // should denote the chain family. Acceptable values are EVM, COSMOS, SOLANA, STARKNET, APTOS etc + WSRPCs []string // websocket rpcs to connect to the chain + HTTPRPCs []string // http rpcs to connect to the chain + DeployerKey *bind.TransactOpts // key to send transactions to the chain } func NewChains(logger logger.Logger, configs []ChainConfig) (map[uint64]deployment.Chain, error) { @@ -52,10 +48,9 @@ func NewChains(logger logger.Logger, configs []ChainConfig) (map[uint64]deployme return nil, fmt.Errorf("failed to connect to chain %s", chainCfg.ChainName) } chains[selector] = deployment.Chain{ - Selector: selector, - Client: ec, - DeployerKey: chainCfg.DeployerKey, - LatestBlockNum: ec.BlockNumber, + Selector: selector, + Client: ec, + DeployerKey: chainCfg.DeployerKey, Confirm: func(tx *types.Transaction) (uint64, error) { var blockNumber uint64 if tx == nil { @@ -64,9 +59,13 @@ func NewChains(logger logger.Logger, configs []ChainConfig) (map[uint64]deployme err := retry.Do(context.Background(), retry.WithMaxDuration(3*time.Minute, retry.NewFibonacci(1*time.Second)), func(ctx context.Context) error { - receipt, err := ec.TransactionReceipt(ctx, tx.Hash()) + chainId, err := ec.ChainID(ctx) if err != nil { - return retry.RetryableError(fmt.Errorf("failed to get receipt: %w", err)) + return fmt.Errorf("failed to get chain id: %w", err) + } + receipt, err := bind.WaitMined(ctx, ec, tx) + if err != nil { + return retry.RetryableError(fmt.Errorf("failed to get receipt for chain %d: %w", chainId, err)) } if receipt != nil { blockNumber = receipt.BlockNumber.Uint64() @@ -90,32 +89,3 @@ func NewChains(logger logger.Logger, configs []ChainConfig) (map[uint64]deployme } return chains, nil } - -// TODO : Remove this when seth is integrated. -func FundAddress(ctx context.Context, from *bind.TransactOpts, to common.Address, amount *big.Int, c deployment.Chain) error { - nonce, err := c.Client.PendingNonceAt(ctx, from.From) - if err != nil { - return fmt.Errorf("failed to get nonce: %w", err) - } - gp, err := c.Client.SuggestGasPrice(ctx) - if err != nil { - return fmt.Errorf("failed to suggest gas price: %w", err) - } - rawTx := types.NewTx(&types.LegacyTx{ - Nonce: nonce, - GasPrice: gp, - Gas: 21000, - To: &to, - Value: amount, - }) - signedTx, err := from.Signer(from.From, rawTx) - if err != nil { - return fmt.Errorf("failed to sign tx: %w", err) - } - err = c.Client.SendTransaction(ctx, signedTx) - if err != nil { - return fmt.Errorf("failed to send tx: %w", err) - } - _, err = c.Confirm(signedTx) - return err -} diff --git a/integration-tests/deployment/devenv/don.go b/integration-tests/deployment/devenv/don.go index 663f4c3329a..ab64eab5c5e 100644 --- a/integration-tests/deployment/devenv/don.go +++ b/integration-tests/deployment/devenv/don.go @@ -3,17 +3,14 @@ package devenv import ( "context" "fmt" - "math/big" "strconv" "strings" "github.com/AlekSi/pointer" - "github.com/ethereum/go-ethereum/common" "github.com/hashicorp/go-multierror" - chainselectors "github.com/smartcontractkit/chain-selectors" + "github.com/rs/zerolog" clclient "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/deployment" nodev1 "github.com/smartcontractkit/chainlink/integration-tests/deployment/jd/node/v1" "github.com/smartcontractkit/chainlink/integration-tests/deployment/jd/shared/ptypes" "github.com/smartcontractkit/chainlink/integration-tests/web/sdk/client" @@ -38,6 +35,18 @@ type DON struct { Nodes []Node } +func (don *DON) PluginNodes() []Node { + var pluginNodes []Node + for _, node := range don.Nodes { + for _, label := range node.labels { + if label.Key == NodeLabelKeyType && pointer.GetString(label.Value) == NodeLabelValuePlugin { + pluginNodes = append(pluginNodes, node) + } + } + } + return pluginNodes +} + func (don *DON) NodeIds() []string { var nodeIds []string for _, node := range don.Nodes { @@ -46,27 +55,6 @@ func (don *DON) NodeIds() []string { return nodeIds } -func (don *DON) FundNodes(ctx context.Context, amount *big.Int, chains map[uint64]deployment.Chain) error { - var err error - for sel, chain := range chains { - for _, node := range don.Nodes { - // if node is bootstrap, no need to fund it - if node.multiAddr != "" { - continue - } - accountAddr, ok := node.AccountAddr[sel] - if !ok { - err = multierror.Append(err, fmt.Errorf("node %s has no account address for chain %d", node.Name, sel)) - continue - } - if err1 := FundAddress(ctx, chain.DeployerKey, common.HexToAddress(accountAddr), amount, chain); err1 != nil { - err = multierror.Append(err, err1) - } - } - } - return err -} - func (don *DON) CreateSupportedChains(ctx context.Context, chains []ChainConfig) error { var err error for i, node := range don.Nodes { @@ -129,24 +117,30 @@ func NewNode(nodeInfo NodeInfo) (*Node, error) { Password: nodeInfo.CLConfig.Password, }) if err != nil { - return nil, fmt.Errorf("failed to create FMS client: %w", err) + return nil, fmt.Errorf("failed to create node graphql client: %w", err) + } + chainlinkClient, err := clclient.NewChainlinkClient(&nodeInfo.CLConfig, zerolog.Logger{}) + if err != nil { + return nil, fmt.Errorf("failed to create node rest client: %w", err) } return &Node{ - gqlClient: gqlClient, - Name: nodeInfo.Name, - adminAddr: nodeInfo.AdminAddr, + gqlClient: gqlClient, + restClient: chainlinkClient, + Name: nodeInfo.Name, + adminAddr: nodeInfo.AdminAddr, }, nil } type Node struct { - NodeId string // node id returned by job distributor after node is registered with it - JDId string // job distributor id returned by node after Job distributor is created in node - Name string // name of the node - AccountAddr map[uint64]string // chain selector to node's account address mapping for supported chains - gqlClient client.Client // graphql client to interact with the node - labels []*ptypes.Label // labels with which the node is registered with the job distributor - adminAddr string // admin address to send payments to, applicable only for non-bootstrap nodes - multiAddr string // multi address denoting node's FQN (needed for deriving P2PBootstrappers in OCR), applicable only for bootstrap nodes + NodeId string // node id returned by job distributor after node is registered with it + JDId string // job distributor id returned by node after Job distributor is created in node + Name string // name of the node + AccountAddr map[uint64]string // chain selector to node's account address mapping for supported chains + gqlClient client.Client // graphql client to interact with the node + restClient *clclient.ChainlinkClient // rest client to interact with the node + labels []*ptypes.Label // labels with which the node is registered with the job distributor + adminAddr string // admin address to send payments to, applicable only for non-bootstrap nodes + multiAddr string // multi address denoting node's FQN (needed for deriving P2PBootstrappers in OCR), applicable only for bootstrap nodes } // CreateCCIPOCRSupportedChains creates a JobDistributorChainConfig for the node. @@ -156,10 +150,6 @@ type Node struct { func (n *Node) CreateCCIPOCRSupportedChains(ctx context.Context, chains []ChainConfig) error { for _, chain := range chains { chainId := strconv.FormatUint(chain.ChainID, 10) - selector, err := chainselectors.SelectorFromChainId(chain.ChainID) - if err != nil { - return fmt.Errorf("failed to get selector from chain id %d: %w", chain.ChainID, err) - } accountAddr, err := n.gqlClient.FetchAccountAddress(ctx, chainId) if err != nil { return fmt.Errorf("failed to fetch account address for node %s: %w", n.Name, err) @@ -170,7 +160,7 @@ func (n *Node) CreateCCIPOCRSupportedChains(ctx context.Context, chains []ChainC if n.AccountAddr == nil { n.AccountAddr = make(map[uint64]string) } - n.AccountAddr[selector] = *accountAddr + n.AccountAddr[chain.ChainID] = *accountAddr peerID, err := n.gqlClient.FetchP2PPeerID(ctx) if err != nil { return fmt.Errorf("failed to fetch peer id for node %s: %w", n.Name, err) @@ -286,3 +276,7 @@ func (n *Node) SetUpAndLinkJobDistributor(ctx context.Context, jd JobDistributor n.JDId = id return nil } + +func (n *Node) ExportEVMKeysForChain(chainId string) ([]*clclient.ExportedEVMKey, error) { + return n.restClient.ExportEVMKeysForChain(chainId) +} diff --git a/integration-tests/deployment/devenv/environment.go b/integration-tests/deployment/devenv/environment.go index a62f7f5e84f..f7513798e37 100644 --- a/integration-tests/deployment/devenv/environment.go +++ b/integration-tests/deployment/devenv/environment.go @@ -14,9 +14,10 @@ const ( ) type EnvironmentConfig struct { - Chains []ChainConfig - nodeInfo []NodeInfo - JDConfig JDConfig + Chains []ChainConfig + HomeChainSelector uint64 + nodeInfo []NodeInfo + JDConfig JDConfig } func NewEnvironment(ctx context.Context, lggr logger.Logger, config EnvironmentConfig) (*deployment.Environment, *DON, error) { diff --git a/integration-tests/deployment/environment.go b/integration-tests/deployment/environment.go index 8d8fc909a93..0f3c85a3627 100644 --- a/integration-tests/deployment/environment.go +++ b/integration-tests/deployment/environment.go @@ -45,9 +45,8 @@ type Chain struct { Selector uint64 Client OnchainClient // Note the Sign function can be abstract supporting a variety of key storage mechanisms (e.g. KMS etc). - DeployerKey *bind.TransactOpts - LatestBlockNum func(ctx context.Context) (uint64, error) - Confirm func(tx *types.Transaction) (uint64, error) + DeployerKey *bind.TransactOpts + Confirm func(tx *types.Transaction) (uint64, error) } type Environment struct { diff --git a/integration-tests/deployment/memory/environment.go b/integration-tests/deployment/memory/environment.go index 5ae94464940..409e8d3a816 100644 --- a/integration-tests/deployment/memory/environment.go +++ b/integration-tests/deployment/memory/environment.go @@ -41,9 +41,6 @@ func NewMemoryChains(t *testing.T, numChains int) map[uint64]deployment.Chain { Selector: sel, Client: chain.Backend, DeployerKey: chain.DeployerKey, - LatestBlockNum: func(ctx context.Context) (uint64, error) { - return chain.Backend.Blockchain().CurrentBlock().Number.Uint64(), nil - }, Confirm: func(tx *types.Transaction) (uint64, error) { if tx == nil { return 0, fmt.Errorf("tx was nil, nothing to confirm") diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index a26c72a853b..bd3a458165c 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -24,6 +24,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/testreporters" "github.com/smartcontractkit/chainlink-testing-framework/lib/testsummary" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/osutil" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" ) @@ -409,29 +410,29 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { b.te.rpcProviders[networkConfig.ChainID] = &rpcProvider b.te.EVMNetworks = append(b.te.EVMNetworks, &networkConfig) } + if b.clNodesCount > 0 { + dereferrencedEvms := make([]blockchain.EVMNetwork, 0) + for _, en := range b.te.EVMNetworks { + dereferrencedEvms = append(dereferrencedEvms, *en) + } - dereferrencedEvms := make([]blockchain.EVMNetwork, 0) - for _, en := range b.te.EVMNetworks { - dereferrencedEvms = append(dereferrencedEvms, *en) - } - - nodeConfigInToml := b.testConfig.GetNodeConfig() + nodeConfigInToml := b.testConfig.GetNodeConfig() - nodeConfig, _, err := node.BuildChainlinkNodeConfig( - dereferrencedEvms, - nodeConfigInToml.BaseConfigTOML, - nodeConfigInToml.CommonChainConfigTOML, - nodeConfigInToml.ChainConfigTOMLByChainID, - ) - if err != nil { - return nil, err - } + nodeConfig, _, err := node.BuildChainlinkNodeConfig( + dereferrencedEvms, + nodeConfigInToml.BaseConfigTOML, + nodeConfigInToml.CommonChainConfigTOML, + nodeConfigInToml.ChainConfigTOMLByChainID, + ) + if err != nil { + return nil, err + } - err = b.te.StartClCluster(nodeConfig, b.clNodesCount, b.secretsConfig, b.testConfig, b.clNodesOpts...) - if err != nil { - return nil, err + err = b.te.StartClCluster(nodeConfig, b.clNodesCount, b.secretsConfig, b.testConfig, b.clNodesOpts...) + if err != nil { + return nil, err + } } - b.te.isSimulatedNetwork = true return b.te, nil diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index d6c65f3c0e6..759e8eac1ec 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -73,8 +73,9 @@ func Test0002_InitialDeployOnLocal(t *testing.T) { if src == dest { continue } - block, err := destChain.LatestBlockNum(testcontext.Get(t)) + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) require.NoError(t, err) + block := latesthdr.Number.Uint64() startBlocks[dest] = &block seqNum := ccipdeployment.SendRequest(t, e, state, src, dest, false) expectedSeqNum[dest] = seqNum diff --git a/integration-tests/testconfig/ccip/ccip.toml b/integration-tests/testconfig/ccip/ccip.toml index cc8d82f2468..3a27d0cd54d 100644 --- a/integration-tests/testconfig/ccip/ccip.toml +++ b/integration-tests/testconfig/ccip/ccip.toml @@ -1,3 +1,7 @@ +[Common] +# chainlink node funding in native token +chainlink_node_funding = 1 + [Network] selected_networks = ['SIMULATED_1', 'SIMULATED_2'] @@ -86,6 +90,8 @@ DeltaReconcile = '5s' """ [CCIP] +HomeChainSelector = '12922642891491394802' # for chain-2337 + [CCIP.CLNode] NoOfPluginNodes = 4 NoOfBootstraps = 1 diff --git a/integration-tests/testconfig/ccip/config.go b/integration-tests/testconfig/ccip/config.go index a5b168bec2f..b9d969fed1f 100644 --- a/integration-tests/testconfig/ccip/config.go +++ b/integration-tests/testconfig/ccip/config.go @@ -1,6 +1,8 @@ package ccip import ( + "strconv" + "github.com/AlekSi/pointer" ctfconfig "github.com/smartcontractkit/chainlink-testing-framework/lib/config" @@ -21,6 +23,7 @@ type Config struct { PrivateEthereumNetworks map[string]*ctfconfig.EthereumNetworkConfig `toml:",omitempty"` CLNode *NodeConfig `toml:",omitempty"` JobDistributorConfig JDConfig `toml:",omitempty"` + HomeChainSelector *string `toml:",omitempty"` } type NodeConfig struct { @@ -90,3 +93,7 @@ func (o *Config) GetJDDBVersion() string { } return dbversion } + +func (o *Config) GetHomeChainSelector() (uint64, error) { + return strconv.ParseUint(pointer.GetString(o.HomeChainSelector), 10, 64) +} diff --git a/integration-tests/testconfig/ccip/overrides/sepolia_avax_binance.toml b/integration-tests/testconfig/ccip/overrides/sepolia_avax_binance.toml new file mode 100644 index 00000000000..06af64d5d91 --- /dev/null +++ b/integration-tests/testconfig/ccip/overrides/sepolia_avax_binance.toml @@ -0,0 +1,55 @@ +[Common] +# chainlink node funding in native token +chainlink_node_funding = 2 + +[Logging] +test_log_collect = true + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persisted +log_targets = ["loki"] + +[Network] +selected_networks = ['SEPOLIA', 'AVALANCHE_FUJI', 'BSC_TESTNET'] + +[Network.EVMNetworks.SEPOLIA] +evm_name = 'Sepolia Testnet' +evm_chain_id = 11155111 +evm_simulated = false +client_implementation = 'Ethereum' +evm_chainlink_transaction_limit = 5000 +evm_transaction_timeout = '5m' +evm_minimum_confirmations = 1 +evm_gas_estimation_buffer = 1000 +evm_supports_eip1559 = true +evm_default_gas_limit = 6000000 +evm_finality_tag = true + +[Network.EVMNetworks.AVALANCHE_FUJI] +evm_name = 'Avalanche Fuji' +evm_chain_id = 43113 +evm_simulated = false +client_implementation = 'Ethereum' +evm_chainlink_transaction_limit = 5000 +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 + +[Network.EVMNetworks.BSC_TESTNET] +evm_name = 'BSC Testnet' +evm_chain_id = 97 +evm_simulated = false +client_implementation = 'BSC' +evm_chainlink_transaction_limit = 5000 +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] +HomeChainSelector = '16015286601757825753' # for sepolia \ No newline at end of file From e9a9444dcd35af65a8fd8243c49a1e21cd316a17 Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Thu, 19 Sep 2024 18:29:29 +0200 Subject: [PATCH 08/20] [TT-1345] option to use predeployed contracts in OCR tests (#13758) * working version * unify the config a bit, make it possible to use also pre-configured contracts * use Seth's contract loader * fix getting number of contracts to deploy from config * fix configuration logic in ocrv2 smoke/soak tests * uncomment ocr2 plugins * rename some methods, add contract-related information to readme * fix lints --- integration-tests/actions/actions.go | 110 +++++++---- integration-tests/actions/contracts.go | 23 +++ integration-tests/actions/ocr_helpers.go | 8 +- integration-tests/chaos/ocr_chaos_test.go | 4 +- .../contracts/ethereum_contracts.go | 59 +++--- integration-tests/crib/ocr_test.go | 24 ++- integration-tests/load/ocr/ocr_test.go | 8 +- integration-tests/load/ocr/vu.go | 14 +- integration-tests/smoke/forwarder_ocr_test.go | 11 +- .../smoke/forwarders_ocr2_test.go | 8 +- integration-tests/smoke/ocr2_test.go | 26 +-- integration-tests/smoke/ocr_test.go | 6 +- integration-tests/testconfig/README.md | 90 +++++++++ .../testconfig/forwarder_ocr/example.toml | 10 +- .../forwarder_ocr/forwarder_ocr.toml | 9 +- .../testconfig/forwarder_ocr2/example.toml | 22 ++- .../forwarder_ocr2/forwarder_ocr2.toml | 7 +- integration-tests/testconfig/ocr/example.toml | 7 +- integration-tests/testconfig/ocr/ocr.go | 186 +++++++++++++++++- integration-tests/testconfig/ocr/ocr.toml | 5 +- .../testconfig/ocr2/example.toml | 7 +- integration-tests/testconfig/ocr2/ocr2.go | 39 +--- integration-tests/testconfig/ocr2/ocr2.toml | 5 +- integration-tests/testconfig/testconfig.go | 6 + integration-tests/testsetups/ocr.go | 49 ++--- 25 files changed, 538 insertions(+), 205 deletions(-) create mode 100644 integration-tests/actions/contracts.go diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index 198fa8e0dc8..f864d9e7100 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -50,6 +50,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/testconfig/ocr" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_factory" @@ -610,29 +611,48 @@ func TrackForwarder( Msg("Forwarder tracked") } -// DeployOCRv2Contracts deploys a number of OCRv2 contracts and configures them with defaults -func DeployOCRv2Contracts( +// SetupOCRv2Contracts deploys a number of OCRv2 contracts and configures them with defaults +func SetupOCRv2Contracts( l zerolog.Logger, seth *seth.Client, - numberOfContracts int, + ocrContractsConfig ocr.OffChainAggregatorsConfig, linkTokenAddress common.Address, transmitters []string, ocrOptions contracts.OffchainOptions, ) ([]contracts.OffchainAggregatorV2, error) { var ocrInstances []contracts.OffchainAggregatorV2 - for contractCount := 0; contractCount < numberOfContracts; contractCount++ { - ocrInstance, err := contracts.DeployOffchainAggregatorV2( - l, - seth, - linkTokenAddress, - ocrOptions, - ) - if err != nil { - return nil, fmt.Errorf("OCRv2 instance deployment have failed: %w", err) + + if ocrContractsConfig == nil { + return nil, fmt.Errorf("you need to pass non-nil OffChainAggregatorsConfig to setup OCR contracts") + } + + if !ocrContractsConfig.UseExistingOffChainAggregatorsContracts() { + for contractCount := 0; contractCount < ocrContractsConfig.NumberOfContractsToDeploy(); contractCount++ { + ocrInstance, err := contracts.DeployOffchainAggregatorV2( + l, + seth, + linkTokenAddress, + ocrOptions, + ) + if err != nil { + return nil, fmt.Errorf("OCRv2 instance deployment have failed: %w", err) + } + ocrInstances = append(ocrInstances, &ocrInstance) + if (contractCount+1)%ContractDeploymentInterval == 0 { // For large amounts of contract deployments, space things out some + time.Sleep(2 * time.Second) + } } - ocrInstances = append(ocrInstances, &ocrInstance) - if (contractCount+1)%ContractDeploymentInterval == 0 { // For large amounts of contract deployments, space things out some - time.Sleep(2 * time.Second) + } else { + for _, address := range ocrContractsConfig.OffChainAggregatorsContractsAddresses() { + ocrInstance, err := contracts.LoadOffchainAggregatorV2(l, seth, address) + if err != nil { + return nil, fmt.Errorf("OCRv2 instance loading have failed: %w", err) + } + ocrInstances = append(ocrInstances, &ocrInstance) + } + + if !ocrContractsConfig.ConfigureExistingOffChainAggregatorsContracts() { + return ocrInstances, nil } } @@ -781,7 +801,7 @@ func StartNewRound( func DeployOCRContractsForwarderFlow( logger zerolog.Logger, seth *seth.Client, - numberOfContracts int, + ocrContractsConfig ocr.OffChainAggregatorsConfig, linkTokenContractAddress common.Address, workerNodes []contracts.ChainlinkNodeWithKeysAndAddress, forwarderAddresses []common.Address, @@ -802,23 +822,23 @@ func DeployOCRContractsForwarderFlow( return forwarderAddresses, nil } - return deployAnyOCRv1Contracts(logger, seth, numberOfContracts, linkTokenContractAddress, workerNodes, transmitterPayeesFn, transmitterAddressesFn) + return setupAnyOCRv1Contracts(logger, seth, ocrContractsConfig, linkTokenContractAddress, workerNodes, transmitterPayeesFn, transmitterAddressesFn) } -// DeployOCRv1Contracts deploys and funds a certain number of offchain aggregator contracts -func DeployOCRv1Contracts( +// SetupOCRv1Contracts deploys and funds a certain number of offchain aggregator contracts or uses existing ones and returns a slice of contract wrappers. +func SetupOCRv1Contracts( logger zerolog.Logger, seth *seth.Client, - numberOfContracts int, + ocrContractsConfig ocr.OffChainAggregatorsConfig, linkTokenContractAddress common.Address, workerNodes []contracts.ChainlinkNodeWithKeysAndAddress, ) ([]contracts.OffchainAggregator, error) { transmitterPayeesFn := func() (transmitters []string, payees []string, err error) { transmitters = make([]string, 0) payees = make([]string, 0) - for _, node := range workerNodes { + for _, n := range workerNodes { var addr string - addr, err = node.PrimaryEthAddress() + addr, err = n.PrimaryEthAddress() if err != nil { err = fmt.Errorf("error getting node's primary ETH address: %w", err) return @@ -832,8 +852,8 @@ func DeployOCRv1Contracts( transmitterAddressesFn := func() ([]common.Address, error) { transmitterAddresses := make([]common.Address, 0) - for _, node := range workerNodes { - primaryAddress, err := node.PrimaryEthAddress() + for _, n := range workerNodes { + primaryAddress, err := n.PrimaryEthAddress() if err != nil { return nil, err } @@ -843,28 +863,48 @@ func DeployOCRv1Contracts( return transmitterAddresses, nil } - return deployAnyOCRv1Contracts(logger, seth, numberOfContracts, linkTokenContractAddress, workerNodes, transmitterPayeesFn, transmitterAddressesFn) + return setupAnyOCRv1Contracts(logger, seth, ocrContractsConfig, linkTokenContractAddress, workerNodes, transmitterPayeesFn, transmitterAddressesFn) } -func deployAnyOCRv1Contracts( +func setupAnyOCRv1Contracts( logger zerolog.Logger, seth *seth.Client, - numberOfContracts int, + ocrContractsConfig ocr.OffChainAggregatorsConfig, linkTokenContractAddress common.Address, workerNodes []contracts.ChainlinkNodeWithKeysAndAddress, getTransmitterAndPayeesFn func() ([]string, []string, error), getTransmitterAddressesFn func() ([]common.Address, error), ) ([]contracts.OffchainAggregator, error) { - // Deploy contracts var ocrInstances []contracts.OffchainAggregator - for contractCount := 0; contractCount < numberOfContracts; contractCount++ { - ocrInstance, err := contracts.DeployOffchainAggregator(logger, seth, linkTokenContractAddress, contracts.DefaultOffChainAggregatorOptions()) - if err != nil { - return nil, fmt.Errorf("OCR instance deployment have failed: %w", err) + + if ocrContractsConfig == nil { + return nil, fmt.Errorf("you need to pass non-nil OffChainAggregatorsConfig to setup OCR contracts") + } + + if !ocrContractsConfig.UseExistingOffChainAggregatorsContracts() { + // Deploy contracts + for contractCount := 0; contractCount < ocrContractsConfig.NumberOfContractsToDeploy(); contractCount++ { + ocrInstance, err := contracts.DeployOffchainAggregator(logger, seth, linkTokenContractAddress, contracts.DefaultOffChainAggregatorOptions()) + if err != nil { + return nil, fmt.Errorf("OCR instance deployment have failed: %w", err) + } + ocrInstances = append(ocrInstances, &ocrInstance) + if (contractCount+1)%ContractDeploymentInterval == 0 { // For large amounts of contract deployments, space things out some + time.Sleep(2 * time.Second) + } } - ocrInstances = append(ocrInstances, &ocrInstance) - if (contractCount+1)%ContractDeploymentInterval == 0 { // For large amounts of contract deployments, space things out some - time.Sleep(2 * time.Second) + } else { + // Load contract wrappers + for _, address := range ocrContractsConfig.OffChainAggregatorsContractsAddresses() { + ocrInstance, err := contracts.LoadOffChainAggregator(logger, seth, address) + if err != nil { + return nil, fmt.Errorf("OCR instance loading have failed: %w", err) + } + ocrInstances = append(ocrInstances, &ocrInstance) + } + + if !ocrContractsConfig.ConfigureExistingOffChainAggregatorsContracts() { + return ocrInstances, nil } } diff --git a/integration-tests/actions/contracts.go b/integration-tests/actions/contracts.go new file mode 100644 index 00000000000..1a50c4d7ba9 --- /dev/null +++ b/integration-tests/actions/contracts.go @@ -0,0 +1,23 @@ +package actions + +import ( + "github.com/rs/zerolog" + + "github.com/smartcontractkit/chainlink-testing-framework/seth" + + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" +) + +// LinkTokenContract returns a link token contract instance. Depending on test configuration, it either deploys a new one or uses an existing one. +func LinkTokenContract(l zerolog.Logger, sethClient *seth.Client, configWithLinkToken tc.LinkTokenContractConfig) (*contracts.EthereumLinkToken, error) { + if configWithLinkToken != nil && configWithLinkToken.UseExistingLinkTokenContract() { + linkAddress, err := configWithLinkToken.LinkTokenContractAddress() + if err != nil { + return nil, err + } + + return contracts.LoadLinkTokenContract(l, sethClient, linkAddress) + } + return contracts.DeployLinkTokenContract(l, sethClient) +} diff --git a/integration-tests/actions/ocr_helpers.go b/integration-tests/actions/ocr_helpers.go index 19cad817b75..0f6f65d1289 100644 --- a/integration-tests/actions/ocr_helpers.go +++ b/integration-tests/actions/ocr_helpers.go @@ -21,6 +21,8 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink/integration-tests/testconfig/ocr" ) // This actions file often returns functions, rather than just values. These are used as common test helpers, and are @@ -229,13 +231,14 @@ func BuildNodeContractPairID(node contracts.ChainlinkNodeWithKeysAndAddress, ocr func SetupOCRv1Cluster( l zerolog.Logger, seth *seth.Client, + configWithLinkToken tc.LinkTokenContractConfig, workerNodes []*client.ChainlinkK8sClient, ) (common.Address, error) { err := FundChainlinkNodesFromRootAddress(l, seth, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes), big.NewFloat(3)) if err != nil { return common.Address{}, err } - linkContract, err := contracts.DeployLinkTokenContract(l, seth) + linkContract, err := LinkTokenContract(l, seth, configWithLinkToken) if err != nil { return common.Address{}, err } @@ -246,11 +249,12 @@ func SetupOCRv1Feed( l zerolog.Logger, seth *seth.Client, lta common.Address, + ocrContractsConfig ocr.OffChainAggregatorsConfig, msClient *ctfClient.MockserverClient, bootstrapNode *client.ChainlinkK8sClient, workerNodes []*client.ChainlinkK8sClient, ) ([]contracts.OffchainAggregator, error) { - ocrInstances, err := DeployOCRv1Contracts(l, seth, 1, lta, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes)) + ocrInstances, err := SetupOCRv1Contracts(l, seth, ocrContractsConfig, lta, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes)) if err != nil { return nil, err } diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index 7ef03d98c8a..821d3cc48c0 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -179,13 +179,13 @@ func TestOCRChaos(t *testing.T) { }) ms := ctfClient.ConnectMockServer(testEnvironment) - linkContract, err := contracts.DeployLinkTokenContract(l, seth) + linkContract, err := actions.LinkTokenContract(l, seth, config.OCR) require.NoError(t, err, "Error deploying link token contract") err = actions.FundChainlinkNodesFromRootAddress(l, seth, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(chainlinkNodes), big.NewFloat(10)) require.NoError(t, err) - ocrInstances, err := actions.DeployOCRv1Contracts(l, seth, 1, common.HexToAddress(linkContract.Address()), contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes)) + ocrInstances, err := actions.SetupOCRv1Contracts(l, seth, config.OCR, common.HexToAddress(linkContract.Address()), contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes)) require.NoError(t, err) err = actions.CreateOCRJobs(ocrInstances, bootstrapNode, workerNodes, 5, ms, fmt.Sprint(seth.ChainID)) require.NoError(t, err) diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go index c2f86286faf..288a36978a8 100644 --- a/integration-tests/contracts/ethereum_contracts.go +++ b/integration-tests/contracts/ethereum_contracts.go @@ -204,22 +204,17 @@ type EthereumOffchainAggregator struct { l zerolog.Logger } -func LoadOffchainAggregator(l zerolog.Logger, seth *seth.Client, contractAddress common.Address) (EthereumOffchainAggregator, error) { - abi, err := offchainaggregator.OffchainAggregatorMetaData.GetAbi() - if err != nil { - return EthereumOffchainAggregator{}, fmt.Errorf("failed to get OffChain Aggregator ABI: %w", err) - } - seth.ContractStore.AddABI("OffChainAggregator", *abi) - seth.ContractStore.AddBIN("OffChainAggregator", common.FromHex(offchainaggregator.OffchainAggregatorMetaData.Bin)) +func LoadOffChainAggregator(l zerolog.Logger, sethClient *seth.Client, contractAddress common.Address) (EthereumOffchainAggregator, error) { + loader := seth.NewContractLoader[offchainaggregator.OffchainAggregator](sethClient) + instance, err := loader.LoadContract("LinkToken", contractAddress, offchainaggregator.OffchainAggregatorMetaData.GetAbi, offchainaggregator.NewOffchainAggregator) - ocr, err := offchainaggregator.NewOffchainAggregator(contractAddress, wrappers.MustNewWrappedContractBackend(nil, seth)) if err != nil { - return EthereumOffchainAggregator{}, fmt.Errorf("failed to instantiate OCR instance: %w", err) + return EthereumOffchainAggregator{}, fmt.Errorf("failed to instantiate OCR v2 instance: %w", err) } return EthereumOffchainAggregator{ - client: seth, - ocr: ocr, + client: sethClient, + ocr: instance, address: &contractAddress, l: l, }, nil @@ -357,10 +352,6 @@ func (o *EthereumOffchainAggregator) SetConfig( return err } - // fails with error setting OCR config for contract '0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82': both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified - // but we only have gasPrice set... It also fails with the same error when we enable EIP-1559 - // fails when we wait for it to be minted, inside the wrapper there's no error when we call it, so it must be something inside smart contract - // that's reverting it and maybe the error message is completely off _, err = o.client.Decode(o.ocr.SetConfig(o.client.NewTXOpts(), signers, transmitters, threshold, encodedConfigVersion, encodedConfig)) return err } @@ -584,36 +575,36 @@ type EthereumOffchainAggregatorV2 struct { l zerolog.Logger } -func LoadOffChainAggregatorV2(l zerolog.Logger, seth *seth.Client, contractAddress common.Address) (EthereumOffchainAggregatorV2, error) { - oAbi, err := ocr2aggregator.OCR2AggregatorMetaData.GetAbi() +func LoadOffchainAggregatorV2(l zerolog.Logger, seth *seth.Client, address common.Address) (EthereumOffchainAggregatorV2, error) { + contractAbi, err := ocr2aggregator.OCR2AggregatorMetaData.GetAbi() if err != nil { - return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to get OffChain Aggregator ABI: %w", err) + return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to get OffChain Aggregator v2 ABI: %w", err) } - seth.ContractStore.AddABI("OffChainAggregatorV2", *oAbi) + seth.ContractStore.AddABI("OffChainAggregatorV2", *contractAbi) seth.ContractStore.AddBIN("OffChainAggregatorV2", common.FromHex(ocr2aggregator.OCR2AggregatorMetaData.Bin)) - ocr2, err := ocr2aggregator.NewOCR2Aggregator(contractAddress, seth.Client) + ocr2, err := ocr2aggregator.NewOCR2Aggregator(address, seth.Client) if err != nil { - return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to instantiate OCR instance: %w", err) + return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to instantiate OCRv2 instance: %w", err) } return EthereumOffchainAggregatorV2{ client: seth, contract: ocr2, - address: &contractAddress, + address: &address, l: l, }, nil } func DeployOffchainAggregatorV2(l zerolog.Logger, seth *seth.Client, linkTokenAddress common.Address, offchainOptions OffchainOptions) (EthereumOffchainAggregatorV2, error) { - oAbi, err := ocr2aggregator.OCR2AggregatorMetaData.GetAbi() + contractAbi, err := ocr2aggregator.OCR2AggregatorMetaData.GetAbi() if err != nil { - return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to get OffChain Aggregator ABI: %w", err) + return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to get OffChain Aggregator v2 ABI: %w", err) } - seth.ContractStore.AddABI("OffChainAggregatorV2", *oAbi) + seth.ContractStore.AddABI("OffChainAggregatorV2", *contractAbi) seth.ContractStore.AddBIN("OffChainAggregatorV2", common.FromHex(ocr2aggregator.OCR2AggregatorMetaData.Bin)) - ocrDeploymentData2, err := seth.DeployContract(seth.NewTXOpts(), "OffChainAggregatorV2", *oAbi, common.FromHex(ocr2aggregator.OCR2AggregatorMetaData.Bin), + ocrDeploymentData2, err := seth.DeployContract(seth.NewTXOpts(), "OffChainAggregatorV2", *contractAbi, common.FromHex(ocr2aggregator.OCR2AggregatorMetaData.Bin), linkTokenAddress, offchainOptions.MinimumAnswer, offchainOptions.MaximumAnswer, @@ -624,12 +615,12 @@ func DeployOffchainAggregatorV2(l zerolog.Logger, seth *seth.Client, linkTokenAd ) if err != nil { - return EthereumOffchainAggregatorV2{}, fmt.Errorf("OCR instance deployment have failed: %w", err) + return EthereumOffchainAggregatorV2{}, fmt.Errorf("OCRv2 instance deployment have failed: %w", err) } ocr2, err := ocr2aggregator.NewOCR2Aggregator(ocrDeploymentData2.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) if err != nil { - return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to instantiate OCR instance: %w", err) + return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to instantiate OCRv2 instance: %w", err) } return EthereumOffchainAggregatorV2{ @@ -772,22 +763,16 @@ func DeployLinkTokenContract(l zerolog.Logger, client *seth.Client) (*EthereumLi } func LoadLinkTokenContract(l zerolog.Logger, client *seth.Client, address common.Address) (*EthereumLinkToken, error) { - linkABI, err := link_token_interface.LinkTokenMetaData.GetAbi() - if err != nil { - return &EthereumLinkToken{}, fmt.Errorf("failed to get LinkToken ABI: %w", err) - } + loader := seth.NewContractLoader[link_token_interface.LinkToken](client) + instance, err := loader.LoadContract("LinkToken", address, link_token_interface.LinkTokenMetaData.GetAbi, link_token_interface.NewLinkToken) - 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)) if err != nil { return &EthereumLinkToken{}, fmt.Errorf("failed to instantiate LinkToken instance: %w", err) } return &EthereumLinkToken{ client: client, - instance: linkToken, + instance: instance, address: address, l: l, }, nil diff --git a/integration-tests/crib/ocr_test.go b/integration-tests/crib/ocr_test.go index 69804e24d77..215734c318e 100644 --- a/integration-tests/crib/ocr_test.go +++ b/integration-tests/crib/ocr_test.go @@ -8,25 +8,30 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/havoc" "github.com/smartcontractkit/chainlink-testing-framework/lib/client" + "github.com/smartcontractkit/chainlink-testing-framework/lib/logging" + "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/ptr" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink-testing-framework/lib/logging" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + ocr_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/ocr" ) // TestCRIBChaos an example of how we can run chaos tests with havoc and core CRIB func TestCRIBChaos(t *testing.T) { l := logging.GetTestLogger(t) + config, err := tc.GetConfig([]string{"Crib"}, tc.OCR) + require.NoError(t, err) sethClient, msClient, bootstrapNode, workerNodes, _, err := ConnectRemote() require.NoError(t, err) - lta, err := actions.SetupOCRv1Cluster(l, sethClient, workerNodes) + lta, err := actions.SetupOCRv1Cluster(l, sethClient, config.OCR, workerNodes) require.NoError(t, err) - ocrInstances, err := actions.SetupOCRv1Feed(l, sethClient, lta, msClient, bootstrapNode, workerNodes) + ocrInstances, err := actions.SetupOCRv1Feed(l, sethClient, lta, config.OCR, msClient, bootstrapNode, workerNodes) require.NoError(t, err) err = actions.SetAllAdapterResponsesToTheSameValue(10, ocrInstances, workerNodes, msClient) @@ -41,11 +46,12 @@ func TestCRIBChaos(t *testing.T) { 1*time.Second, os.Getenv("CRIB_NAMESPACE"), ) + require.NoError(t, err, "Error rebooting CL namespace") ch.Create(context.Background()) ch.AddListener(havoc.NewChaosLogger(l)) t.Cleanup(func() { err := ch.Delete(context.Background()) - require.NoError(t, err) + require.NoError(t, err, "Error deleting chaos") }) require.Eventually(t, func() bool { err = actions.WatchNewOCRRound(l, sethClient, 3, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), 5*time.Minute) @@ -65,9 +71,15 @@ func TestCRIBRPCChaos(t *testing.T) { sethClient, msClient, bootstrapNode, workerNodes, vars, err := ConnectRemote() require.NoError(t, err) - lta, err := actions.SetupOCRv1Cluster(l, sethClient, workerNodes) + ocrConfig := &ocr_config.Config{ + Contracts: &ocr_config.Contracts{ + ShouldBeUsed: ptr.Ptr(false), + }, + } + + lta, err := actions.SetupOCRv1Cluster(l, sethClient, ocrConfig, workerNodes) require.NoError(t, err) - ocrInstances, err := actions.SetupOCRv1Feed(l, sethClient, lta, msClient, bootstrapNode, workerNodes) + ocrInstances, err := actions.SetupOCRv1Feed(l, sethClient, lta, ocrConfig, msClient, bootstrapNode, workerNodes) require.NoError(t, err) err = actions.SetAllAdapterResponsesToTheSameValue(10, ocrInstances, workerNodes, msClient) diff --git a/integration-tests/load/ocr/ocr_test.go b/integration-tests/load/ocr/ocr_test.go index 281d2da2bb1..55b683a0a74 100644 --- a/integration-tests/load/ocr/ocr_test.go +++ b/integration-tests/load/ocr/ocr_test.go @@ -31,9 +31,9 @@ func TestOCRLoad(t *testing.T) { sethClient, msClient, bootstrapNode, workerNodes, _, err := crib.ConnectRemote() require.NoError(t, err) - lta, err := actions.SetupOCRv1Cluster(l, sethClient, workerNodes) + lta, err := actions.SetupOCRv1Cluster(l, sethClient, config.OCR, workerNodes) require.NoError(t, err) - ocrInstances, err := actions.SetupOCRv1Feed(l, sethClient, lta, msClient, bootstrapNode, workerNodes) + ocrInstances, err := actions.SetupOCRv1Feed(l, sethClient, lta, config.OCR, msClient, bootstrapNode, workerNodes) require.NoError(t, err) cfg := config.OCR @@ -64,7 +64,7 @@ func TestOCRVolume(t *testing.T) { sethClient, msClient, bootstrapNode, workerNodes, _, err := crib.ConnectRemote() require.NoError(t, err) - lta, err := actions.SetupOCRv1Cluster(l, sethClient, workerNodes) + lta, err := actions.SetupOCRv1Cluster(l, sethClient, config.OCR, workerNodes) require.NoError(t, err) cfg := config.OCR @@ -77,7 +77,7 @@ func TestOCRVolume(t *testing.T) { LoadType: wasp.VU, CallTimeout: cfg.Volume.VerificationTimeout.Duration, Schedule: wasp.Plain(*cfg.Volume.Rate, cfg.Volume.TestDuration.Duration), - VU: NewVU(l, sethClient, *cfg.Volume.VURequestsPerUnit, cfg.Volume.RateLimitUnitDuration.Duration, lta, bootstrapNode, workerNodes, msClient), + VU: NewVU(l, sethClient, cfg, *cfg.Volume.VURequestsPerUnit, cfg.Volume.RateLimitUnitDuration.Duration, lta, bootstrapNode, workerNodes, msClient), Labels: CommonTestLabels, LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })) diff --git a/integration-tests/load/ocr/vu.go b/integration-tests/load/ocr/vu.go index aece9cb74b1..c337e338a82 100644 --- a/integration-tests/load/ocr/vu.go +++ b/integration-tests/load/ocr/vu.go @@ -8,18 +8,16 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" - - "github.com/smartcontractkit/chainlink-testing-framework/seth" - "go.uber.org/ratelimit" - "github.com/smartcontractkit/chainlink-testing-framework/wasp" - client2 "github.com/smartcontractkit/chainlink-testing-framework/lib/client" + "github.com/smartcontractkit/chainlink-testing-framework/seth" + "github.com/smartcontractkit/chainlink-testing-framework/wasp" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/testconfig/ocr" ) // VU is a virtual user for the OCR load test @@ -37,11 +35,13 @@ type VU struct { msClient *client2.MockserverClient l zerolog.Logger ocrInstances []contracts.OffchainAggregator + config ocr.OffChainAggregatorsConfig } func NewVU( l zerolog.Logger, seth *seth.Client, + config ocr.OffChainAggregatorsConfig, rate int, rateUnit time.Duration, lta common.Address, @@ -60,6 +60,7 @@ func NewVU( msClient: msClient, bootstrapNode: bootstrapNode, workerNodes: workerNodes, + config: config, } } @@ -75,11 +76,12 @@ func (m *VU) Clone(_ *wasp.Generator) wasp.VirtualUser { msClient: m.msClient, bootstrapNode: m.bootstrapNode, workerNodes: m.workerNodes, + config: m.config, } } func (m *VU) Setup(_ *wasp.Generator) error { - ocrInstances, err := actions.DeployOCRv1Contracts(m.l, m.seth, 1, m.lta, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(m.workerNodes)) + ocrInstances, err := actions.SetupOCRv1Contracts(m.l, m.seth, m.config, m.lta, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(m.workerNodes)) if err != nil { return err } diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go index 4441a592886..5e5fb1d40b6 100644 --- a/integration-tests/smoke/forwarder_ocr_test.go +++ b/integration-tests/smoke/forwarder_ocr_test.go @@ -60,8 +60,8 @@ func TestForwarderOCRBasic(t *testing.T) { _ = actions.ReturnFundsFromNodes(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(env.ClCluster.NodeAPIs())) }) - lt, err := contracts.DeployLinkTokenContract(l, sethClient) - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") + linkContract, err := actions.LinkTokenContract(l, sethClient, config.OCR) + require.NoError(t, err, "Error loading/deploying link token contract") fundingAmount := big.NewFloat(.05) l.Info().Str("ETH amount per node", fundingAmount.String()).Msg("Funding Chainlink nodes") @@ -69,7 +69,7 @@ func TestForwarderOCRBasic(t *testing.T) { require.NoError(t, err, "Error funding Chainlink nodes") operators, authorizedForwarders, _ := actions.DeployForwarderContracts( - t, sethClient, common.HexToAddress(lt.Address()), len(workerNodes), + t, sethClient, common.HexToAddress(linkContract.Address()), len(workerNodes), ) require.Equal(t, len(workerNodes), len(operators), "Number of operators should match number of worker nodes") @@ -81,11 +81,12 @@ func TestForwarderOCRBasic(t *testing.T) { require.NoError(t, err, "Accepting Authorize Receivers on Operator shouldn't fail") actions.TrackForwarder(t, sethClient, authorizedForwarders[i], workerNodes[i]) } + ocrInstances, err := actions.DeployOCRContractsForwarderFlow( l, sethClient, - 1, - common.HexToAddress(lt.Address()), + config.OCR, + common.HexToAddress(linkContract.Address()), contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes), authorizedForwarders, ) diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go index 219df9ce432..0cc7d9fafe4 100644 --- a/integration-tests/smoke/forwarders_ocr2_test.go +++ b/integration-tests/smoke/forwarders_ocr2_test.go @@ -61,8 +61,8 @@ func TestForwarderOCR2Basic(t *testing.T) { _ = actions.ReturnFundsFromNodes(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(env.ClCluster.NodeAPIs())) }) - lt, err := contracts.DeployLinkTokenContract(l, sethClient) - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") + linkContract, err := actions.LinkTokenContract(l, sethClient, config.OCR2) + require.NoError(t, err, "Error loading/deploying link token contract") fundingAmount := big.NewFloat(.05) l.Info().Str("ETH amount per node", fundingAmount.String()).Msg("Funding Chainlink nodes") @@ -70,7 +70,7 @@ func TestForwarderOCR2Basic(t *testing.T) { require.NoError(t, err, "Error funding Chainlink nodes") operators, authorizedForwarders, _ := actions.DeployForwarderContracts( - t, sethClient, common.HexToAddress(lt.Address()), len(workerNodes), + t, sethClient, common.HexToAddress(linkContract.Address()), len(workerNodes), ) require.Equal(t, len(workerNodes), len(operators), "Number of operators should match number of worker nodes") @@ -90,7 +90,7 @@ func TestForwarderOCR2Basic(t *testing.T) { } ocrOffchainOptions := contracts.DefaultOffChainAggregatorOptions() - ocrInstances, err := actions.DeployOCRv2Contracts(l, sethClient, 1, common.HexToAddress(lt.Address()), transmitters, ocrOffchainOptions) + ocrInstances, err := actions.SetupOCRv2Contracts(l, sethClient, config.OCR2, common.HexToAddress(linkContract.Address()), transmitters, ocrOffchainOptions) require.NoError(t, err, "Error deploying OCRv2 contracts with forwarders") ocrv2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffchainOptions) diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 3203037ae55..325c88f979a 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -103,11 +103,11 @@ func TestOCRv2JobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - env, aggregatorContracts, sethClient := prepareORCv2SmokeTestEnv(t, defaultTestData(), l, 5) - nodeClients := env.ClCluster.NodeAPIs() + testEnv, aggregatorContracts, sethClient := prepareORCv2SmokeTestEnv(t, defaultTestData(), l, 5) + nodeClients := testEnv.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] - err := env.MockAdapter.SetAdapterBasedIntValuePath("ocr2", []string{http.MethodGet, http.MethodPost}, 10) + err := testEnv.MockAdapter.SetAdapterBasedIntValuePath("ocr2", []string{http.MethodGet, http.MethodPost}, 10) require.NoError(t, err) err = actions.WatchNewOCRRound(l, sethClient, 2, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) require.NoError(t, err, "Error watching for new OCR2 round") @@ -125,7 +125,7 @@ func TestOCRv2JobReplacement(t *testing.T) { err = actions.DeleteBridges(nodeClients) require.NoError(t, err) - err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 15, uint64(sethClient.ChainID), false, false) + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, testEnv.MockAdapter, "ocr2", 15, uint64(sethClient.ChainID), false, false) require.NoError(t, err, "Error creating OCRv2 jobs") err = actions.WatchNewOCRRound(l, sethClient, 3, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*3) @@ -170,8 +170,8 @@ func prepareORCv2SmokeTestEnv(t *testing.T, testData ocr2test, l zerolog.Logger, nodeClients := testEnv.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] - linkContract, err := contracts.DeployLinkTokenContract(l, sethClient) - require.NoError(t, err, "Error deploying link token contract") + linkContract, err := actions.LinkTokenContract(l, sethClient, config.OCR2) + require.NoError(t, err, "Error loading/deploying link token contract") err = actions.FundChainlinkNodesFromRootAddress(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes), big.NewFloat(*config.Common.ChainlinkNodeFunding)) require.NoError(t, err, "Error funding Chainlink nodes") @@ -191,18 +191,20 @@ func prepareORCv2SmokeTestEnv(t *testing.T, testData ocr2test, l zerolog.Logger, transmitters = append(transmitters, addr) } - ocrOffchainOptions := contracts.DefaultOffChainAggregatorOptions() - aggregatorContracts, err := actions.DeployOCRv2Contracts(l, sethClient, 1, common.HexToAddress(linkContract.Address()), transmitters, ocrOffchainOptions) + ocrOffChainOptions := contracts.DefaultOffChainAggregatorOptions() + aggregatorContracts, err := actions.SetupOCRv2Contracts(l, sethClient, config.OCR2, common.HexToAddress(linkContract.Address()), transmitters, ocrOffChainOptions) require.NoError(t, err, "Error deploying OCRv2 aggregator contracts") err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, testEnv.MockAdapter, "ocr2", 5, uint64(sethClient.ChainID), false, testData.chainReaderAndCodec) require.NoError(t, err, "Error creating OCRv2 jobs") - ocrv2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffchainOptions) - require.NoError(t, err, "Error building OCRv2 config") + if !config.OCR2.UseExistingOffChainAggregatorsContracts() || (config.OCR2.UseExistingOffChainAggregatorsContracts() && config.OCR2.ConfigureExistingOffChainAggregatorsContracts()) { + ocrV2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffChainOptions) + require.NoError(t, err, "Error building OCRv2 config") - err = actions.ConfigureOCRv2AggregatorContracts(ocrv2Config, aggregatorContracts) - require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") + err = actions.ConfigureOCRv2AggregatorContracts(ocrV2Config, aggregatorContracts) + require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") + } assertCorrectNodeConfiguration(t, l, clNodeCount, testData, testEnv) diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index cd9db0e9740..a19adb5c022 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -113,10 +113,10 @@ func prepareORCv1SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult i _ = actions.ReturnFundsFromNodes(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(env.ClCluster.NodeAPIs())) }) - linkContract, err := contracts.DeployLinkTokenContract(l, sethClient) - require.NoError(t, err, "Error deploying link token contract") + linkContract, err := actions.LinkTokenContract(l, sethClient, config.OCR) + require.NoError(t, err, "Error loading/deploying link token contract") - ocrInstances, err := actions.DeployOCRv1Contracts(l, sethClient, 1, common.HexToAddress(linkContract.Address()), contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes)) + ocrInstances, err := actions.SetupOCRv1Contracts(l, sethClient, config.OCR, common.HexToAddress(linkContract.Address()), contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes)) require.NoError(t, err, "Error deploying OCR contracts") err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, big.NewInt(sethClient.ChainID)) diff --git a/integration-tests/testconfig/README.md b/integration-tests/testconfig/README.md index c698281b76e..f6186580550 100644 --- a/integration-tests/testconfig/README.md +++ b/integration-tests/testconfig/README.md @@ -194,6 +194,96 @@ BumpMin = '100 gwei' 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. +### OCR tests contract config +In order to allow running OCR soak/load/smoke tests with already deployed contracts, we have provided an experimental feature for providing addresses of LINK token and OCR contracts in the TOML config. Additionally, user can choose, whether existing OCR contracts should be configured or not. +If no contract addresses are provided, the tests will deploy new contracts. + +The feature is highly configurable and it possible to use existing LINK token contract, but deploy new OCR contracts or vice versa. Both OCRv1 and OCRv2 contracts are supported. + +To use existing LINK and OCRv1 contracts, provide the following configuration in the TOML file: +```toml +[OCR.Contracts] +link_token = "0x88d1239894D9582f5849E5b5a964da9e5730f1E6" +offchain_aggregators = ["0xc1ce3815d6e7f3705265c2577F1342344752A5Eb"] +``` + +For OCRv2, provide the following configuration: +```toml +[OCR2.Contracts] +link_token = "0x88d1239894D9582f5849E5b5a964da9e5730f1E6" +offchain_aggregators = ["0xc1ce3815d6e7f3705265c2577F1342344752A5Eb"] +``` + +If you want to disable them, you can set `use = false` or remove the addresses from the configuration. + +If you want to use existing OCRv1 contract, without configuring it, you can set `configure = false` in the configuration: +```toml +[OCR.Contracts] +link_token = "0x88d1239894D9582f5849E5b5a964da9e5730f1E6" +offchain_aggregators = ["0xc1ce3815d6e7f3705265c2577F1342344752A5Eb"] + +# notice that this address needs to match the one in offchain_aggregators +[OCR.Contracts.Settings."0xc1ce3815d6e7f3705265c2577F1342344752A5Eb"] +configure = false +``` + +Be aware that using multiple existing OCR contracts, but configuring only some of them is not supported. This is not a valid configuration: +```toml +[OCR.Contracts] +link_token = "0x88d1239894D9582f5849E5b5a964da9e5730f1E6" +offchain_aggregators = ["0xc1ce3815d6e7f3705265c2577F1342344752A5Eb", "0x2f4FA21fCd917C448C160caafEC874032F404c08"] + +# notice that this address needs to match the one in offchain_aggregators +[OCR.Contracts.Settings."0xc1ce3815d6e7f3705265c2577F1342344752A5Eb"] +configure = false + +# if setting for a given address is not present, we assume it should be used and configured +# so in this case "0x2f4FA21fCd917C448C160caafEC874032F404c08" will be evaluated as configure = true, +# but "0xc1ce3815d6e7f3705265c2577F1342344752A5Eb" is set to configure = false. +# this will fail configuration validation +``` + +This, more explicit version is also invalid: +```toml +[OCR.Contracts] +link_token = "0x88d1239894D9582f5849E5b5a964da9e5730f1E6" +offchain_aggregators = ["0xc1ce3815d6e7f3705265c2577F1342344752A5Eb", "0x2f4FA21fCd917C448C160caafEC874032F404c08"] + +# notice that this address needs to match the one in offchain_aggregators +[OCR.Contracts.Settings."0xc1ce3815d6e7f3705265c2577F1342344752A5Eb"] +configure = false + +[OCR.Contracts.Settings."0x2f4FA21fCd917C448C160caafEC874032F404c08"] +configure = true +``` + +Similarly, this one is also invalid: +```toml +[OCR.Contracts] +link_token = "0x88d1239894D9582f5849E5b5a964da9e5730f1E6" +offchain_aggregators = ["0xc1ce3815d6e7f3705265c2577F1342344752A5Eb", "0x2f4FA21fCd917C448C160caafEC874032F404c08"] + +# notice that this address needs to match the one in offchain_aggregators +[OCR.Contracts.Settings."0xc1ce3815d6e7f3705265c2577F1342344752A5Eb"] +use = false + +[OCR.Contracts.Settings."0x2f4FA21fCd917C448C160caafEC874032F404c08"] +use = true +``` + +There are no settings available for LINK token contract. + +Last, but not least, when deploying new OCR contracts you need to provide their number. For example: +```toml +# for OCRv1 +[OCR.Common] +number_of_contracts=2 + +# for OCRv2 +[OCR2.Common] +number_of_contracts=2 +``` + ### Setting env vars for Chainlink Node To set env vars for Chainlink Node use `WithCLNodeOptions()` and `WithNodeEnvVars()` when building a test environment. Example: diff --git a/integration-tests/testconfig/forwarder_ocr/example.toml b/integration-tests/testconfig/forwarder_ocr/example.toml index 0b762299af1..75143d7b77f 100644 --- a/integration-tests/testconfig/forwarder_ocr/example.toml +++ b/integration-tests/testconfig/forwarder_ocr/example.toml @@ -31,7 +31,7 @@ bearer_token_secret="bearer_token" base_url="http://grafana.url" # url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard dashboard_url="/d/your-dashboard" -# Grafana dashboard uid to annotate. Find it in Dashboard Settings -> JSON Model +# Grafana dashboard uid to annotate. Find it in Dashboard Settings -> JSON Model dashboard_uid="dashboard-uid-to-annotate" bearer_token_secret="my-awesome-token" @@ -143,6 +143,9 @@ BumpPercent = 20 BumpMin = '100 gwei' """ +[OCR.Common] +number_of_contracts=1 + # load test specific configuration [Load.OCR] [Load.OCR.Common] @@ -162,9 +165,8 @@ chainlink_node_funding = 100 [Soak.OCR] [Soak.OCR.Common] +number_of_contracts=2 test_duration="15m" [Soak.OCR.Soak] -ocr_version="1" -number_of_contracts=2 -time_between_rounds="1m" \ No newline at end of file +time_between_rounds="1m" diff --git a/integration-tests/testconfig/forwarder_ocr/forwarder_ocr.toml b/integration-tests/testconfig/forwarder_ocr/forwarder_ocr.toml index 8fa0fa5db25..68ed21404f3 100644 --- a/integration-tests/testconfig/forwarder_ocr/forwarder_ocr.toml +++ b/integration-tests/testconfig/forwarder_ocr/forwarder_ocr.toml @@ -57,7 +57,10 @@ MinContractPayment = 0 [Transactions] ForwardersEnabled = true - """ +""" + +[OCR.Common] +number_of_contracts=1 # load test specific configuration [Load.OCR] @@ -92,8 +95,8 @@ chainlink_node_funding = 0.5 [Soak.OCR] [Soak.OCR.Common] +number_of_contracts=2 test_duration = "15m" [Soak.OCR.Soak] -number_of_contracts = 2 -time_between_rounds = "1m" +time_between_rounds="1m" diff --git a/integration-tests/testconfig/forwarder_ocr2/example.toml b/integration-tests/testconfig/forwarder_ocr2/example.toml index b3bc45d270c..4941c49a983 100644 --- a/integration-tests/testconfig/forwarder_ocr2/example.toml +++ b/integration-tests/testconfig/forwarder_ocr2/example.toml @@ -31,7 +31,7 @@ bearer_token_secret="bearer_token" base_url="http://grafana.url" # url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard dashboard_url="/d/your-dashboard" -# Grafana dashboard uid to annotate. Find it in Dashboard Settings -> JSON Model +# Grafana dashboard uid to annotate. Find it in Dashboard Settings -> JSON Model dashboard_uid="dashboard-uid-to-annotate" bearer_token_secret="my-awesome-token" @@ -143,12 +143,15 @@ BumpPercent = 20 BumpMin = '100 gwei' """ +[OCR2.Common] +number_of_contracts=1 + # load test specific configuration -[Load.OCR] -[Load.OCR.Common] +[Load.OCR2] +[Load.OCR2.Common] eth_funds = 3 -[Load.OCR.Load] +[Load.OCR2.Load] test_duration = "3m" rate_limit_unit_duration = "1m" rate = 3 @@ -160,11 +163,10 @@ ea_change_interval = "5s" [Soak.Common] chainlink_node_funding = 100 -[Soak.OCR] -[Soak.OCR.Common] +[Soak.OCR2] +[Soak.OCR2.Common] +number_of_contracts=2 test_duration="15m" -[Soak.OCR.Soak] -ocr_version="1" -number_of_contracts=2 -time_between_rounds="1m" \ No newline at end of file +[Soak.OCR2.Soak] +time_between_rounds="1m" diff --git a/integration-tests/testconfig/forwarder_ocr2/forwarder_ocr2.toml b/integration-tests/testconfig/forwarder_ocr2/forwarder_ocr2.toml index 3f2a8610a83..76d5695a8b6 100644 --- a/integration-tests/testconfig/forwarder_ocr2/forwarder_ocr2.toml +++ b/integration-tests/testconfig/forwarder_ocr2/forwarder_ocr2.toml @@ -53,7 +53,10 @@ MinContractPayment = 0 [Transactions] ForwardersEnabled = true - """ +""" + +[OCR2.Common] +number_of_contracts=1 # load test specific configuration [Load.OCR2.Common] @@ -85,10 +88,10 @@ ea_change_interval = "5s" chainlink_node_funding = 1 [Soak.OCR2.Common] +number_of_contracts=2 test_duration="15m" [Soak.OCR2.Soak] -number_of_contracts=2 time_between_rounds="1m" diff --git a/integration-tests/testconfig/ocr/example.toml b/integration-tests/testconfig/ocr/example.toml index 92262241dff..26f0dd5a84e 100644 --- a/integration-tests/testconfig/ocr/example.toml +++ b/integration-tests/testconfig/ocr/example.toml @@ -31,7 +31,7 @@ bearer_token_secret="bearer_token" base_url="http://grafana.url" # url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard dashboard_url="/d/your-dashboard" -# Grafana dashboard uid to annotate. Find it in Dashboard Settings -> JSON Model +# Grafana dashboard uid to annotate. Find it in Dashboard Settings -> JSON Model dashboard_uid="dashboard-uid-to-annotate" bearer_token_secret="my-awesome-token" @@ -142,6 +142,9 @@ BumpPercent = 20 BumpMin = '100 gwei' """ +[OCR.Common] +number_of_contracts=1 + # load test specific configuration [Load.OCR] [Load.OCR.Common] @@ -161,8 +164,8 @@ chainlink_node_funding = 100 [Soak.OCR] [Soak.OCR.Common] +number_of_contracts=2 test_duration="15m" [Soak.OCR.Soak] -number_of_contracts=2 time_between_rounds="1m" diff --git a/integration-tests/testconfig/ocr/ocr.go b/integration-tests/testconfig/ocr/ocr.go index d8250d407fa..240fd2afeaa 100644 --- a/integration-tests/testconfig/ocr/ocr.go +++ b/integration-tests/testconfig/ocr/ocr.go @@ -2,15 +2,19 @@ package ocr import ( "errors" + "fmt" + + "github.com/ethereum/go-ethereum/common" "github.com/smartcontractkit/chainlink-testing-framework/lib/blockchain" ) type Config struct { - Soak *SoakConfig `toml:"Soak"` - Load *Load `toml:"Load"` - Volume *Volume `toml:"Volume"` - Common *Common `toml:"Common"` + Soak *SoakConfig `toml:"Soak"` + Load *Load `toml:"Load"` + Volume *Volume `toml:"Volume"` + Common *Common `toml:"Common"` + Contracts *Contracts `toml:"Contracts"` } func (o *Config) Validate() error { @@ -29,15 +33,24 @@ func (o *Config) Validate() error { return err } } + if o.Contracts != nil { + if err := o.Contracts.Validate(); err != nil { + return err + } + } return nil } type Common struct { - ETHFunds *int `toml:"eth_funds"` - TestDuration *blockchain.StrDuration `toml:"test_duration"` + NumberOfContracts *int `toml:"number_of_contracts"` + ETHFunds *int `toml:"eth_funds"` + TestDuration *blockchain.StrDuration `toml:"test_duration"` } func (o *Common) Validate() error { + if o.NumberOfContracts != nil && *o.NumberOfContracts < 1 { + return errors.New("when number_of_contracts is set, it must be greater than 0") + } if o.ETHFunds != nil && *o.ETHFunds < 0 { return errors.New("eth_funds must be set and cannot be negative") } @@ -117,16 +130,169 @@ func (o *Volume) Validate() error { } type SoakConfig struct { - NumberOfContracts *int `toml:"number_of_contracts"` TimeBetweenRounds *blockchain.StrDuration `toml:"time_between_rounds"` } func (o *SoakConfig) Validate() error { - if o.NumberOfContracts == nil || *o.NumberOfContracts <= 1 { - return errors.New("number_of_contracts must be set and be greater than 1") - } if o.TimeBetweenRounds == nil || o.TimeBetweenRounds.Duration == 0 { return errors.New("time_between_rounds must be set and be a positive integer") } return nil } + +// For more information on the configuration of contracts, see https://smartcontract-it.atlassian.net/wiki/spaces/TT/pages/828407894/Contracts+addresses+in+TOML+convention +type Contracts struct { + ShouldBeUsed *bool `toml:"use"` + LinkTokenAddress *string `toml:"link_token"` + OffChainAggregatorAddresses []string `toml:"offchain_aggregators"` + Settings map[string]ContractSetting `toml:"Settings"` +} + +func (o *Contracts) Validate() error { + if o.LinkTokenAddress != nil && !common.IsHexAddress(*o.LinkTokenAddress) { + return errors.New("link_token must be a valid ethereum address") + } + if o.OffChainAggregatorAddresses != nil { + allEnabled := make(map[bool]int) + allConfigure := make(map[bool]int) + for _, address := range o.OffChainAggregatorAddresses { + if !common.IsHexAddress(address) { + return fmt.Errorf("offchain_aggregators must be valid ethereum addresses, but %s is not", address) + } + + if v, ok := o.Settings[address]; ok { + if v.ShouldBeUsed != nil { + allEnabled[*v.ShouldBeUsed]++ + } else { + allEnabled[true]++ + } + if v.Configure != nil { + allConfigure[*v.Configure]++ + } else { + allConfigure[true]++ + } + } + } + + if allEnabled[true] > 0 && allEnabled[false] > 0 { + return errors.New("either all or none offchain_aggregators must be used") + } + + if allConfigure[true] > 0 && allConfigure[false] > 0 { + return errors.New("either all or none offchain_aggregators must be configured") + } + } + + return nil +} + +func (o *Config) UseExistingContracts() bool { + if o.Contracts == nil { + return false + } + + if o.Contracts.ShouldBeUsed != nil { + return *o.Contracts.ShouldBeUsed + } + + return false +} + +func (o *Config) LinkTokenContractAddress() (common.Address, error) { + if o.Contracts != nil && o.Contracts.LinkTokenAddress != nil { + return common.HexToAddress(*o.Contracts.LinkTokenAddress), nil + } + + return common.Address{}, errors.New("link token address must be set") +} + +func (o *Config) UseExistingLinkTokenContract() bool { + if !o.UseExistingContracts() { + return false + } + + if o.Contracts.LinkTokenAddress == nil { + return false + } + + if len(o.Contracts.Settings) == 0 { + return true + } + + if v, ok := o.Contracts.Settings[*o.Contracts.LinkTokenAddress]; ok { + return v.ShouldBeUsed != nil && *v.ShouldBeUsed + } + + return true +} + +type ContractSetting struct { + ShouldBeUsed *bool `toml:"use"` + Configure *bool `toml:"configure"` +} + +type OffChainAggregatorsConfig interface { + OffChainAggregatorsContractsAddresses() []common.Address + UseExistingOffChainAggregatorsContracts() bool + ConfigureExistingOffChainAggregatorsContracts() bool + NumberOfContractsToDeploy() int +} + +func (o *Config) UseExistingOffChainAggregatorsContracts() bool { + if !o.UseExistingContracts() { + return false + } + + if len(o.Contracts.OffChainAggregatorAddresses) == 0 { + return false + } + + if len(o.Contracts.Settings) == 0 { + return true + } + + for _, address := range o.Contracts.OffChainAggregatorAddresses { + if v, ok := o.Contracts.Settings[address]; ok { + return v.ShouldBeUsed != nil && *v.ShouldBeUsed + } + } + + return true +} + +func (o *Config) OffChainAggregatorsContractsAddresses() []common.Address { + var ocrInstanceAddresses []common.Address + if !o.UseExistingOffChainAggregatorsContracts() { + return ocrInstanceAddresses + } + + for _, address := range o.Contracts.OffChainAggregatorAddresses { + ocrInstanceAddresses = append(ocrInstanceAddresses, common.HexToAddress(address)) + } + + return ocrInstanceAddresses +} + +func (o *Config) ConfigureExistingOffChainAggregatorsContracts() bool { + if !o.UseExistingOffChainAggregatorsContracts() { + return true + } + + for _, address := range o.Contracts.OffChainAggregatorAddresses { + for maybeOcrAddress, setting := range o.Contracts.Settings { + if maybeOcrAddress == address { + return setting.Configure != nil && *setting.Configure + } + } + } + + return true +} + +func (o *Config) NumberOfContractsToDeploy() int { + if o.Common != nil && o.Common.NumberOfContracts != nil { + return *o.Common.NumberOfContracts + } + + return 0 +} diff --git a/integration-tests/testconfig/ocr/ocr.toml b/integration-tests/testconfig/ocr/ocr.toml index 17ee4d7b687..36cded0b85c 100644 --- a/integration-tests/testconfig/ocr/ocr.toml +++ b/integration-tests/testconfig/ocr/ocr.toml @@ -43,6 +43,9 @@ Enabled = true ListenAddresses = ['0.0.0.0:6690'] """ +[OCR.Common] +number_of_contracts=1 + # load test specific configuration [Load.OCR] [Load.OCR.Common] @@ -77,9 +80,9 @@ chainlink_node_funding = 0.5 [Soak.OCR] [Soak.OCR.Common] test_duration="15m" +number_of_contracts=2 [Soak.OCR.Soak] -number_of_contracts=2 time_between_rounds="1m" # Soak test configuration with Geth reorg below finality with FinalityTagEnabled=false diff --git a/integration-tests/testconfig/ocr2/example.toml b/integration-tests/testconfig/ocr2/example.toml index 36e3105f219..624c3b77752 100644 --- a/integration-tests/testconfig/ocr2/example.toml +++ b/integration-tests/testconfig/ocr2/example.toml @@ -31,7 +31,7 @@ bearer_token_secret="bearer_token" base_url="http://grafana.url" # url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard dashboard_url="/d/your-dashboard" -# Grafana dashboard uid to annotate. Find it in Dashboard Settings -> JSON Model +# Grafana dashboard uid to annotate. Find it in Dashboard Settings -> JSON Model dashboard_uid="dashboard-uid-to-annotate" bearer_token_secret="my-awesome-token" @@ -142,6 +142,9 @@ BumpPercent = 20 BumpMin = '100 gwei' """ +[OCR2.Common] +number_of_contracts=1 + # load test specific configuration [Load.OCR2] [Load.OCR2.Common] @@ -161,8 +164,8 @@ chainlink_node_funding = 100 [Soak.OCR2] [Soak.OCR.Common] +number_of_contracts=2 test_duration="15m" [Soak.OCR2.Soak] -number_of_contracts=2 time_between_rounds="1m" diff --git a/integration-tests/testconfig/ocr2/ocr2.go b/integration-tests/testconfig/ocr2/ocr2.go index 1e7f034e043..60169e944fa 100644 --- a/integration-tests/testconfig/ocr2/ocr2.go +++ b/integration-tests/testconfig/ocr2/ocr2.go @@ -1,14 +1,13 @@ package ocr2 import ( - "errors" - - "github.com/smartcontractkit/chainlink-testing-framework/lib/blockchain" + "github.com/smartcontractkit/chainlink/integration-tests/testconfig/ocr" ) type Config struct { - Soak *SoakConfig `toml:"Soak"` - Common *Common `toml:"Common"` + Soak *ocr.SoakConfig `toml:"Soak"` + Common *ocr.Common `toml:"Common"` + Contracts *ocr.Contracts `toml:"Contracts"` } func (o *Config) Validate() error { @@ -22,32 +21,10 @@ func (o *Config) Validate() error { return err } } - return nil -} - -type Common struct { - ETHFunds *int `toml:"eth_funds"` - TestDuration *blockchain.StrDuration `toml:"test_duration"` -} - -func (o *Common) Validate() error { - if o.ETHFunds != nil && *o.ETHFunds < 0 { - return errors.New("eth_funds must be set and cannot be negative") - } - return nil -} - -type SoakConfig struct { - NumberOfContracts *int `toml:"number_of_contracts"` - TimeBetweenRounds *blockchain.StrDuration `toml:"time_between_rounds"` -} - -func (o *SoakConfig) Validate() error { - if o.NumberOfContracts == nil || *o.NumberOfContracts <= 1 { - return errors.New("number_of_contracts must be set and be greater than 1") - } - if o.TimeBetweenRounds == nil || o.TimeBetweenRounds.Duration == 0 { - return errors.New("time_between_rounds must be set and be a positive integer") + if o.Contracts != nil { + if err := o.Contracts.Validate(); err != nil { + return err + } } return nil } diff --git a/integration-tests/testconfig/ocr2/ocr2.toml b/integration-tests/testconfig/ocr2/ocr2.toml index ad195913bd0..62d92574ea8 100644 --- a/integration-tests/testconfig/ocr2/ocr2.toml +++ b/integration-tests/testconfig/ocr2/ocr2.toml @@ -43,6 +43,9 @@ Enabled = true ListenAddresses = ['0.0.0.0:6690'] """ +[OCR2.Common] +number_of_contracts=1 + # load test specific configuration [Load.OCR2] [Load.OCR2.Common] @@ -76,8 +79,8 @@ chainlink_node_funding = 0.5 [Soak.OCR2] [Soak.OCR2.Common] +number_of_contracts=2 test_duration="15m" [Soak.OCR2.Soak] -number_of_contracts=2 time_between_rounds="1m" diff --git a/integration-tests/testconfig/testconfig.go b/integration-tests/testconfig/testconfig.go index fb692c56a75..545818e3348 100644 --- a/integration-tests/testconfig/testconfig.go +++ b/integration-tests/testconfig/testconfig.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/barkimedes/go-deepcopy" + "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/pelletier/go-toml/v2" "github.com/pkg/errors" @@ -77,6 +78,11 @@ type CCIPTestConfig interface { GetCCIPConfig() *ccip_config.Config } +type LinkTokenContractConfig interface { + LinkTokenContractAddress() (common.Address, error) + UseExistingLinkTokenContract() bool +} + const ( E2E_TEST_DATA_STREAMS_URL_ENV = "E2E_TEST_DATA_STREAMS_URL" E2E_TEST_DATA_STREAMS_USERNAME_ENV = "E2E_TEST_DATA_STREAMS_USERNAME" diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index 3653b9d5fb9..73b142b6297 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -281,8 +281,8 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { 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) - require.NoError(o.t, err, "Error deploying LINK contract") + linkContract, err := actions.LinkTokenContract(o.log, sethClient, ocrTestConfig.GetActiveOCRConfig()) + require.NoError(o.t, err, "Error loading/deploying link token contract") // Fund Chainlink nodes, excluding the bootstrap node o.log.Info().Float64("ETH amount per node", *o.Config.Common.ChainlinkNodeFunding).Msg("Funding Chainlink nodes") @@ -290,7 +290,6 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { require.NoError(o.t, err, "Error funding Chainlink nodes") var forwarders []common.Address - if o.OperatorForwarderFlow { var operators []common.Address operators, forwarders, _ = actions.DeployForwarderContracts( @@ -311,17 +310,17 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { o.ocrV1Instances, err = actions.DeployOCRContractsForwarderFlow( o.log, o.seth, - *o.Config.GetActiveOCRConfig().Soak.NumberOfContracts, + o.Config.GetActiveOCRConfig(), common.HexToAddress(linkContract.Address()), contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(o.workerNodes), forwarders, ) require.NoError(o.t, err, "Error deploying OCR Forwarder contracts") } else { - o.ocrV1Instances, err = actions.DeployOCRv1Contracts( + o.ocrV1Instances, err = actions.SetupOCRv1Contracts( o.log, sethClient, - *o.Config.GetActiveOCRConfig().Soak.NumberOfContracts, + o.Config.GetActiveOCRConfig(), common.HexToAddress(linkContract.Address()), contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(o.workerNodes), ) @@ -343,19 +342,22 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { } ocrOffchainOptions := contracts.DefaultOffChainAggregatorOptions() - o.ocrV2Instances, err = actions.DeployOCRv2Contracts( + o.ocrV2Instances, err = actions.SetupOCRv2Contracts( o.log, o.seth, - *ocrTestConfig.GetActiveOCRConfig().Soak.NumberOfContracts, + ocrTestConfig.GetActiveOCRConfig(), common.HexToAddress(linkContract.Address()), transmitters, ocrOffchainOptions, ) require.NoError(o.t, err, "Error deploying OCRv2 contracts") - contractConfig, err := actions.BuildMedianOCR2Config(o.workerNodes, ocrOffchainOptions) - require.NoError(o.t, err, "Error building median config") - err = actions.ConfigureOCRv2AggregatorContracts(contractConfig, o.ocrV2Instances) - require.NoError(o.t, err, "Error configuring OCRv2 aggregator contracts") + + if !ocrTestConfig.GetActiveOCRConfig().UseExistingOffChainAggregatorsContracts() || (ocrTestConfig.GetActiveOCRConfig().UseExistingOffChainAggregatorsContracts() && ocrTestConfig.GetActiveOCRConfig().ConfigureExistingOffChainAggregatorsContracts()) { + contractConfig, err := actions.BuildMedianOCR2Config(o.workerNodes, ocrOffchainOptions) + require.NoError(o.t, err, "Error building median config") + err = actions.ConfigureOCRv2AggregatorContracts(contractConfig, o.ocrV2Instances) + require.NoError(o.t, err, "Error configuring OCRv2 aggregator contracts") + } } if o.OCRVersion == "1" { @@ -399,7 +401,7 @@ func (o *OCRSoakTest) Run() { o.log.Info(). Str("Test Duration", o.Config.GetActiveOCRConfig().Common.TestDuration.Duration.Truncate(time.Second).String()). - Int("Number of OCR Contracts", *config.GetActiveOCRConfig().Soak.NumberOfContracts). + Int("Number of OCR Contracts", *config.GetActiveOCRConfig().Common.NumberOfContracts). Str("OCR Version", o.OCRVersion). Msg("Starting OCR Soak Test") @@ -530,7 +532,7 @@ func (o *OCRSoakTest) LoadState() error { if testState.OCRVersion == "1" { o.ocrV1Instances = make([]contracts.OffchainAggregator, len(testState.OCRContractAddresses)) for i, addr := range testState.OCRContractAddresses { - instance, err := contracts.LoadOffchainAggregator(o.log, o.seth, common.HexToAddress(addr)) + instance, err := contracts.LoadOffChainAggregator(o.log, o.seth, common.HexToAddress(addr)) if err != nil { return fmt.Errorf("failed to instantiate OCR instance: %w", err) } @@ -539,7 +541,7 @@ func (o *OCRSoakTest) LoadState() error { } else if testState.OCRVersion == "2" { o.ocrV2Instances = make([]contracts.OffchainAggregatorV2, len(testState.OCRContractAddresses)) for i, addr := range testState.OCRContractAddresses { - instance, err := contracts.LoadOffChainAggregatorV2(o.log, o.seth, common.HexToAddress(addr)) + instance, err := contracts.LoadOffchainAggregatorV2(o.log, o.seth, common.HexToAddress(addr)) if err != nil { return err } @@ -561,7 +563,7 @@ func (o *OCRSoakTest) Resume() { Str("Time Left", o.timeLeft.String()). Msg("Resuming OCR Soak Test") - ocrAddresses := make([]common.Address, *o.Config.GetActiveOCRConfig().Soak.NumberOfContracts) + ocrAddresses := make([]common.Address, *o.Config.GetActiveOCRConfig().Common.NumberOfContracts) if o.OCRVersion == "1" { for i, ocrInstance := range o.ocrV1Instances { @@ -1021,12 +1023,12 @@ func (o *OCRSoakTest) collectEvents() error { // ensureValues ensures that all values needed to run the test are present func (o *OCRSoakTest) ensureInputValues() error { - ocrConfig := o.Config.GetActiveOCRConfig().Soak + ocrConfig := o.Config.GetActiveOCRConfig() if o.OCRVersion != "1" && o.OCRVersion != "2" { return fmt.Errorf("OCR version must be 1 or 2, found %s", o.OCRVersion) } - if ocrConfig.NumberOfContracts != nil && *ocrConfig.NumberOfContracts <= 0 { - return fmt.Errorf("number of OCR contracts must be set and greater than 0, found %d", ocrConfig.NumberOfContracts) + if ocrConfig.Common.NumberOfContracts != nil && *ocrConfig.Common.NumberOfContracts <= 0 { + return fmt.Errorf("number of OCR contracts must be set and greater than 0, found %d", ocrConfig.Common.NumberOfContracts) } if o.Config.Common.ChainlinkNodeFunding != nil && *o.Config.Common.ChainlinkNodeFunding <= 0 { return fmt.Errorf("chainlink node funding must be greater than 0, found %f", *o.Config.Common.ChainlinkNodeFunding) @@ -1034,11 +1036,12 @@ func (o *OCRSoakTest) ensureInputValues() error { if o.Config.GetActiveOCRConfig().Common.TestDuration != nil && o.Config.GetActiveOCRConfig().Common.TestDuration.Duration <= time.Minute { return fmt.Errorf("test duration must be greater than 1 minute, found %s", o.Config.GetActiveOCRConfig().Common.TestDuration) } - if ocrConfig.TimeBetweenRounds != nil && ocrConfig.TimeBetweenRounds.Duration >= time.Hour { - return fmt.Errorf("time between rounds must be less than 1 hour, found %s", ocrConfig.TimeBetweenRounds) + soakConfig := ocrConfig.Soak + if soakConfig.TimeBetweenRounds != nil && soakConfig.TimeBetweenRounds.Duration >= time.Hour { + return fmt.Errorf("time between rounds must be less than 1 hour, found %s", soakConfig.TimeBetweenRounds) } - if ocrConfig.TimeBetweenRounds != nil && ocrConfig.TimeBetweenRounds.Duration < time.Second*30 { - return fmt.Errorf("time between rounds must be greater or equal to 30 seconds, found %s", ocrConfig.TimeBetweenRounds) + if soakConfig.TimeBetweenRounds != nil && soakConfig.TimeBetweenRounds.Duration < time.Second*30 { + return fmt.Errorf("time between rounds must be greater or equal to 30 seconds, found %s", soakConfig.TimeBetweenRounds) } return nil From 0aa59850e08538be11e1b53406e786d15299ec98 Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami <167726375+b-gopalswami@users.noreply.github.com> Date: Thu, 19 Sep 2024 12:32:47 -0400 Subject: [PATCH 09/20] CCIP-3420: Fix IsRequestTriggeredWithinTimeframe (#1445) (#14498) ## Motivation The prior approach to find if there is traffic in a lane was not detecting the transactions properly. It could be due to the `CCIPSendRequestedWatcher` captures the event after it is initiated not any transaction before that. ## Solution The revised approach is to use the FilterCCIPSendRequested by a past derived block number and see if there is any traffic. The block number is derived by this formula: `filterFromBlock = latestBlockNumber - (SkipRequestIfAnotherRequestTriggeredWithin/avgBlockTime)` By this approach, we will be able to find traffic better. https://smartcontract-it.atlassian.net/browse/CCIP-3420 --- .../ccip-tests/actions/ccip_helpers.go | 44 +++++++++++++++++++ .../ccip-tests/load/ccip_loadgen.go | 15 ++++++- .../ccip-tests/testconfig/ccip.go | 3 ++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/integration-tests/ccip-tests/actions/ccip_helpers.go b/integration-tests/ccip-tests/actions/ccip_helpers.go index 06334560e05..da2e870f3ec 100644 --- a/integration-tests/ccip-tests/actions/ccip_helpers.go +++ b/integration-tests/ccip-tests/actions/ccip_helpers.go @@ -1620,6 +1620,8 @@ func (sourceCCIP *SourceCCIPModule) AssertSendRequestedLogFinalized( return finalizedAt, finalizedBlockNum.Uint64(), nil } +// IsRequestTriggeredWithinTimeframe monitors for live events occurring within the specified timeframe. +// Live events refer to those that are triggered after subscribing to the CCIP Send Requested event. func (sourceCCIP *SourceCCIPModule) IsRequestTriggeredWithinTimeframe(timeframe *commonconfig.Duration) *time.Time { if timeframe == nil { return nil @@ -1644,6 +1646,48 @@ func (sourceCCIP *SourceCCIPModule) IsRequestTriggeredWithinTimeframe(timeframe return foundAt } +// IsPastRequestTriggeredWithinTimeframe determines the average block time and calculates the block numbers +// within the specified timeframe. It then uses FilterCCIPSendRequested to identify the past events. +func (sourceCCIP *SourceCCIPModule) IsPastRequestTriggeredWithinTimeframe(ctx context.Context, timeframe *commonconfig.Duration) (*time.Time, error) { + if timeframe == nil { + return nil, nil + } + //var foundAt *time.Time + latestBlock, err := sourceCCIP.Common.ChainClient.LatestBlockNumber(ctx) + if err != nil { + return nil, fmt.Errorf("error while getting latest source block number. Error: %w", err) + } + avgBlockTime, err := sourceCCIP.Common.ChainClient.AvgBlockTime(ctx) + if err != nil { + return nil, fmt.Errorf("error while getting average source block time. Error: %w", err) + } + filterFromBlock := latestBlock - uint64(timeframe.Duration()/avgBlockTime) + + onRampContract, err := evm_2_evm_onramp.NewEVM2EVMOnRamp(common.HexToAddress(sourceCCIP.OnRamp.EthAddress.Hex()), + sourceCCIP.Common.ChainClient.Backend()) + if err != nil { + return nil, fmt.Errorf("error while on ramp contract. Error: %w", err) + } + iterator, err := onRampContract.FilterCCIPSendRequested(&bind.FilterOpts{ + Start: filterFromBlock, + }) + if err != nil { + return nil, fmt.Errorf("error while filtering CCIP send requested starting block number: %d. Error: %w", filterFromBlock, err) + } + defer func() { + _ = iterator.Close() + }() + if iterator.Next() { + hdr, err := sourceCCIP.Common.ChainClient.HeaderByNumber(context.Background(), big.NewInt(int64(iterator.Event.Raw.BlockNumber))) + if err != nil { + return nil, fmt.Errorf("error getting header for block: %d, Error: %w", iterator.Event.Raw.BlockNumber, err) + } + return pointer.ToTime(hdr.Timestamp), nil + } + + return nil, nil +} + func (sourceCCIP *SourceCCIPModule) AssertEventCCIPSendRequested( lggr *zerolog.Logger, txHash string, diff --git a/integration-tests/ccip-tests/load/ccip_loadgen.go b/integration-tests/ccip-tests/load/ccip_loadgen.go index bc7627b4e08..3ce770d31bc 100644 --- a/integration-tests/ccip-tests/load/ccip_loadgen.go +++ b/integration-tests/ccip-tests/load/ccip_loadgen.go @@ -10,6 +10,8 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/AlekSi/pointer" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -222,7 +224,18 @@ func (c *CCIPE2ELoad) CCIPMsg() (router.ClientEVM2AnyMessage, *testreporters.Req func (c *CCIPE2ELoad) Call(_ *wasp.Generator) *wasp.Response { res := &wasp.Response{} sourceCCIP := c.Lane.Source - recentRequestFoundAt := sourceCCIP.IsRequestTriggeredWithinTimeframe(c.SkipRequestIfAnotherRequestTriggeredWithin) + var recentRequestFoundAt *time.Time + var err error + // Use IsPastRequestTriggeredWithinTimeframe to check for any historical CCIP send request events + // within the specified timeframe for the first message. Subsequently, use the watcher method to monitor + // and detect any new events as they occur. + if c.CurrentMsgSerialNo.Load() == int64(1) { + recentRequestFoundAt, err = sourceCCIP.IsPastRequestTriggeredWithinTimeframe(testcontext.Get(c.t), c.SkipRequestIfAnotherRequestTriggeredWithin) + require.NoError(c.t, err, "error while filtering past requests") + } else { + recentRequestFoundAt = sourceCCIP.IsRequestTriggeredWithinTimeframe(c.SkipRequestIfAnotherRequestTriggeredWithin) + } + if recentRequestFoundAt != nil { c.Lane.Logger. Info(). diff --git a/integration-tests/ccip-tests/testconfig/ccip.go b/integration-tests/ccip-tests/testconfig/ccip.go index 76e00ecf496..0a53ee18732 100644 --- a/integration-tests/ccip-tests/testconfig/ccip.go +++ b/integration-tests/ccip-tests/testconfig/ccip.go @@ -242,6 +242,9 @@ func (l *LoadProfile) Validate() error { if l.TestDuration == nil || l.TestDuration.Duration().Minutes() == 0 { return fmt.Errorf("test duration should be set") } + if l.SkipRequestIfAnotherRequestTriggeredWithin != nil && l.TimeUnit.Duration() < l.SkipRequestIfAnotherRequestTriggeredWithin.Duration() { + return fmt.Errorf("SkipRequestIfAnotherRequestTriggeredWithin should be set below the TimeUnit duration") + } return nil } From d2a01ca51bb4a7654d2ceb4f5c25f2ca2de3df11 Mon Sep 17 00:00:00 2001 From: Oliver Townsend <133903322+ogtownsend@users.noreply.github.com> Date: Thu, 19 Sep 2024 09:54:04 -0700 Subject: [PATCH 10/20] Bring KMS client and multiclient over to chainlink (#14484) * Bring KMS client and multiclient over to chainlink * Pull seth client into multiclient * remove toml tags * Keep multiclient simple * Config validation for kms * Rename to ws, fix test * Changeset * Downgrade seth * Lint * More lint --------- Co-authored-by: AnieeG Co-authored-by: connorwstein --- .changeset/sour-ears-wink.md | 5 + .../ccip/ccip_integration_tests/helpers.go | 2 - integration-tests/deployment/evm_kmsclient.go | 233 ++++++++++++++++++ .../deployment/evm_kmsclient_test.go | 27 ++ integration-tests/deployment/multiclient.go | 124 ++++++++++ .../deployment/multiclient_test.go | 36 +++ integration-tests/go.mod | 2 +- 7 files changed, 426 insertions(+), 3 deletions(-) create mode 100644 .changeset/sour-ears-wink.md create mode 100644 integration-tests/deployment/evm_kmsclient.go create mode 100644 integration-tests/deployment/evm_kmsclient_test.go create mode 100644 integration-tests/deployment/multiclient.go create mode 100644 integration-tests/deployment/multiclient_test.go diff --git a/.changeset/sour-ears-wink.md b/.changeset/sour-ears-wink.md new file mode 100644 index 00000000000..d77fd548c51 --- /dev/null +++ b/.changeset/sour-ears-wink.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#internal KMS client for deployment diff --git a/core/capabilities/ccip/ccip_integration_tests/helpers.go b/core/capabilities/ccip/ccip_integration_tests/helpers.go index 25baddfb48e..4670333e391 100644 --- a/core/capabilities/ccip/ccip_integration_tests/helpers.go +++ b/core/capabilities/ccip/ccip_integration_tests/helpers.go @@ -406,7 +406,6 @@ func (h *homeChain) AddNodes( p2pIDs [][32]byte, capabilityIDs [][32]byte, ) { - // Need to sort, otherwise _checkIsValidUniqueSubset onChain will fail sortP2PIDS(p2pIDs) var nodeParams []kcr.CapabilitiesRegistryNodeParams for _, p2pID := range p2pIDs { @@ -430,7 +429,6 @@ func AddChainConfig( 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{ diff --git a/integration-tests/deployment/evm_kmsclient.go b/integration-tests/deployment/evm_kmsclient.go new file mode 100644 index 00000000000..07af77523c8 --- /dev/null +++ b/integration-tests/deployment/evm_kmsclient.go @@ -0,0 +1,233 @@ +package deployment + +import ( + "bytes" + "context" + "crypto/ecdsa" + "encoding/asn1" + "encoding/hex" + "fmt" + "math/big" + + "github.com/aws/aws-sdk-go/aws/session" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/kms" + "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/crypto" + "github.com/ethereum/go-ethereum/crypto/secp256k1" +) + +var ( + secp256k1N = crypto.S256().Params().N + secp256k1HalfN = new(big.Int).Div(secp256k1N, big.NewInt(2)) +) + +// See https://docs.aws.amazon.com/kms/latest/APIReference/API_GetPublicKey.html#API_GetPublicKey_ResponseSyntax +// and https://datatracker.ietf.org/doc/html/rfc5280 for why we need to unpack the KMS public key. +type asn1SubjectPublicKeyInfo struct { + AlgorithmIdentifier asn1AlgorithmIdentifier + SubjectPublicKey asn1.BitString +} + +type asn1AlgorithmIdentifier struct { + Algorithm asn1.ObjectIdentifier + Parameters asn1.ObjectIdentifier +} + +// See https://aws.amazon.com/blogs/database/part2-use-aws-kms-to-securely-manage-ethereum-accounts/ for why we +// need to manually prep the signature for Ethereum. +type asn1ECDSASig struct { + R asn1.RawValue + S asn1.RawValue +} + +// TODO: Mockery gen then test with a regular eth key behind the interface. +type KMSClient interface { + GetPublicKey(input *kms.GetPublicKeyInput) (*kms.GetPublicKeyOutput, error) + Sign(input *kms.SignInput) (*kms.SignOutput, error) +} + +type KMS struct { + KmsDeployerKeyId string + KmsDeployerKeyRegion string + AwsProfileName string +} + +func NewKMSClient(config KMS) (KMSClient, error) { + if config.KmsDeployerKeyId == "" { + return nil, fmt.Errorf("KMS key ID is required") + } + if config.KmsDeployerKeyRegion == "" { + return nil, fmt.Errorf("KMS key region is required") + } + var awsSessionFn AwsSessionFn + if config.AwsProfileName != "" { + awsSessionFn = awsSessionFromProfileFn + } else { + awsSessionFn = awsSessionFromEnvVarsFn + } + return kms.New(awsSessionFn(config)), nil +} + +type EVMKMSClient struct { + Client KMSClient + KeyID string +} + +func NewEVMKMSClient(client KMSClient, keyID string) *EVMKMSClient { + return &EVMKMSClient{ + Client: client, + KeyID: keyID, + } +} + +func (c *EVMKMSClient) GetKMSTransactOpts(ctx context.Context, chainID *big.Int) (*bind.TransactOpts, error) { + ecdsaPublicKey, err := c.GetECDSAPublicKey() + if err != nil { + return nil, err + } + + pubKeyBytes := secp256k1.S256().Marshal(ecdsaPublicKey.X, ecdsaPublicKey.Y) + keyAddr := crypto.PubkeyToAddress(*ecdsaPublicKey) + if chainID == nil { + return nil, fmt.Errorf("chainID is required") + } + signer := types.LatestSignerForChainID(chainID) + + signerFn := func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { + if address != keyAddr { + return nil, bind.ErrNotAuthorized + } + + txHashBytes := signer.Hash(tx).Bytes() + + mType := kms.MessageTypeDigest + algo := kms.SigningAlgorithmSpecEcdsaSha256 + signOutput, err := c.Client.Sign( + &kms.SignInput{ + KeyId: &c.KeyID, + SigningAlgorithm: &algo, + MessageType: &mType, + Message: txHashBytes, + }) + if err != nil { + return nil, fmt.Errorf("failed to call kms.Sign() on transaction: %w", err) + } + + ethSig, err := kmsToEthSig(signOutput.Signature, pubKeyBytes, txHashBytes) + if err != nil { + return nil, fmt.Errorf("failed to convert KMS signature to Ethereum signature: %w", err) + } + + return tx.WithSignature(signer, ethSig) + } + + return &bind.TransactOpts{ + From: keyAddr, + Signer: signerFn, + Context: ctx, + }, nil +} + +// GetECDSAPublicKey retrieves the public key from KMS and converts it to its ECDSA representation. +func (c *EVMKMSClient) GetECDSAPublicKey() (*ecdsa.PublicKey, error) { + getPubKeyOutput, err := c.Client.GetPublicKey(&kms.GetPublicKeyInput{ + KeyId: aws.String(c.KeyID), + }) + if err != nil { + return nil, fmt.Errorf("can not get public key from KMS for KeyId=%s: %w", c.KeyID, err) + } + + var asn1pubKeyInfo asn1SubjectPublicKeyInfo + _, err = asn1.Unmarshal(getPubKeyOutput.PublicKey, &asn1pubKeyInfo) + if err != nil { + return nil, fmt.Errorf("can not parse asn1 public key for KeyId=%s: %w", c.KeyID, err) + } + + pubKey, err := crypto.UnmarshalPubkey(asn1pubKeyInfo.SubjectPublicKey.Bytes) + if err != nil { + return nil, fmt.Errorf("can not unmarshal public key bytes: %w", err) + } + return pubKey, nil +} + +func kmsToEthSig(kmsSig, ecdsaPubKeyBytes, hash []byte) ([]byte, error) { + var asn1Sig asn1ECDSASig + _, err := asn1.Unmarshal(kmsSig, &asn1Sig) + if err != nil { + return nil, err + } + + rBytes := asn1Sig.R.Bytes + sBytes := asn1Sig.S.Bytes + + // Adjust S value from signature to match Eth standard. + // See: https://aws.amazon.com/blogs/database/part2-use-aws-kms-to-securely-manage-ethereum-accounts/ + // "After we extract r and s successfully, we have to test if the value of s is greater than secp256k1n/2 as + // specified in EIP-2 and flip it if required." + sBigInt := new(big.Int).SetBytes(sBytes) + if sBigInt.Cmp(secp256k1HalfN) > 0 { + sBytes = new(big.Int).Sub(secp256k1N, sBigInt).Bytes() + } + + return recoverEthSignature(ecdsaPubKeyBytes, hash, rBytes, sBytes) +} + +// See: https://aws.amazon.com/blogs/database/part2-use-aws-kms-to-securely-manage-ethereum-accounts/ +func recoverEthSignature(expectedPublicKeyBytes, txHash, r, s []byte) ([]byte, error) { + rsSig := append(padTo32Bytes(r), padTo32Bytes(s)...) + ethSig := append(rsSig, []byte{0}...) + + recoveredPublicKeyBytes, err := crypto.Ecrecover(txHash, ethSig) + if err != nil { + return nil, fmt.Errorf("failing to call Ecrecover: %w", err) + } + + if hex.EncodeToString(recoveredPublicKeyBytes) != hex.EncodeToString(expectedPublicKeyBytes) { + ethSig = append(rsSig, []byte{1}...) + recoveredPublicKeyBytes, err = crypto.Ecrecover(txHash, ethSig) + if err != nil { + return nil, fmt.Errorf("failing to call Ecrecover: %w", err) + } + + if hex.EncodeToString(recoveredPublicKeyBytes) != hex.EncodeToString(expectedPublicKeyBytes) { + return nil, fmt.Errorf("can not reconstruct public key from sig") + } + } + + return ethSig, nil +} + +func padTo32Bytes(buffer []byte) []byte { + buffer = bytes.TrimLeft(buffer, "\x00") + for len(buffer) < 32 { + zeroBuf := []byte{0} + buffer = append(zeroBuf, buffer...) + } + return buffer +} + +type AwsSessionFn func(config KMS) *session.Session + +var awsSessionFromEnvVarsFn = func(config KMS) *session.Session { + return session.Must( + session.NewSession(&aws.Config{ + Region: aws.String(config.KmsDeployerKeyRegion), + CredentialsChainVerboseErrors: aws.Bool(true), + })) +} + +var awsSessionFromProfileFn = func(config KMS) *session.Session { + return session.Must( + session.NewSessionWithOptions(session.Options{ + SharedConfigState: session.SharedConfigEnable, + Profile: config.AwsProfileName, + Config: aws.Config{ + Region: aws.String(config.KmsDeployerKeyRegion), + CredentialsChainVerboseErrors: aws.Bool(true), + }, + })) +} diff --git a/integration-tests/deployment/evm_kmsclient_test.go b/integration-tests/deployment/evm_kmsclient_test.go new file mode 100644 index 00000000000..8a889a56067 --- /dev/null +++ b/integration-tests/deployment/evm_kmsclient_test.go @@ -0,0 +1,27 @@ +package deployment + +import ( + "encoding/hex" + "testing" + + "github.com/test-go/testify/require" +) + +func TestKMSToEthSigConversion(t *testing.T) { + kmsSigBytes, err := hex.DecodeString("304402206168865941bafcae3a8cf8b26edbb5693d62222b2e54d962c1aabbeaddf33b6802205edc7f597d2bf2d1eaa14fc514a6202bafcffe52b13ae3fec00674d92a874b73") + require.NoError(t, err) + ecdsaPublicKeyBytes, err := hex.DecodeString("04a735e9e3cb526f83be23b03f1f5ae7788a8654e3f0fcfb4f978290de07ebd47da30eeb72e904fdd4a81b46e320908ff4345e119148f89c1f04674c14a506e24b") + require.NoError(t, err) + txHashBytes, err := hex.DecodeString("a2f037301e90f58c084fe4bec2eef14b26e620d6b6cb46051037d03b29ab7d9a") + require.NoError(t, err) + expectedEthSignBytes, err := hex.DecodeString("6168865941bafcae3a8cf8b26edbb5693d62222b2e54d962c1aabbeaddf33b685edc7f597d2bf2d1eaa14fc514a6202bafcffe52b13ae3fec00674d92a874b7300") + require.NoError(t, err) + + actualEthSig, err := kmsToEthSig( + kmsSigBytes, + ecdsaPublicKeyBytes, + txHashBytes, + ) + require.NoError(t, err) + require.Equal(t, expectedEthSignBytes, actualEthSig) +} diff --git a/integration-tests/deployment/multiclient.go b/integration-tests/deployment/multiclient.go new file mode 100644 index 00000000000..02a18f760df --- /dev/null +++ b/integration-tests/deployment/multiclient.go @@ -0,0 +1,124 @@ +package deployment + +import ( + "context" + "fmt" + "math/big" + "time" + + "github.com/avast/retry-go/v4" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/pkg/errors" +) + +const ( + RPC_DEFAULT_RETRY_ATTEMPTS = 10 + RPC_DEFAULT_RETRY_DELAY = 1000 * time.Millisecond +) + +type RetryConfig struct { + Attempts uint + Delay time.Duration +} + +func defaultRetryConfig() RetryConfig { + return RetryConfig{ + Attempts: RPC_DEFAULT_RETRY_ATTEMPTS, + Delay: RPC_DEFAULT_RETRY_DELAY, + } +} + +type RPC struct { + WSURL string + // TODO: http fallback needed for some networks? +} + +// MultiClient should comply with the OnchainClient interface +var _ OnchainClient = &MultiClient{} + +type MultiClient struct { + *ethclient.Client + Backups []*ethclient.Client + RetryConfig RetryConfig +} + +func NewMultiClient(rpcs []RPC, opts ...func(client *MultiClient)) (*MultiClient, error) { + if len(rpcs) == 0 { + return nil, fmt.Errorf("No RPCs provided, need at least one") + } + var mc MultiClient + clients := make([]*ethclient.Client, 0, len(rpcs)) + for _, rpc := range rpcs { + client, err := ethclient.Dial(rpc.WSURL) + if err != nil { + return nil, errors.Wrapf(err, "failed to dial %s", rpc.WSURL) + } + clients = append(clients, client) + } + mc.Client = clients[0] + mc.Backups = clients[1:] + mc.RetryConfig = defaultRetryConfig() + + for _, opt := range opts { + opt(&mc) + } + return &mc, nil +} + +func (mc *MultiClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { + var receipt *types.Receipt + err := mc.retryWithBackups(func(client *ethclient.Client) error { + var err error + receipt, err = client.TransactionReceipt(ctx, txHash) + return err + }) + return receipt, err +} + +func (mc *MultiClient) SendTransaction(ctx context.Context, tx *types.Transaction) error { + return mc.retryWithBackups(func(client *ethclient.Client) error { + return client.SendTransaction(ctx, tx) + }) +} + +func (mc *MultiClient) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { + var code []byte + err := mc.retryWithBackups(func(client *ethclient.Client) error { + var err error + code, err = client.CodeAt(ctx, account, blockNumber) + return err + }) + return code, err +} + +func (mc *MultiClient) NonceAt(ctx context.Context, account common.Address) (uint64, error) { + var count uint64 + err := mc.retryWithBackups(func(client *ethclient.Client) error { + var err error + count, err = client.NonceAt(ctx, account, nil) + return err + }) + return count, err +} + +func (mc *MultiClient) retryWithBackups(op func(*ethclient.Client) error) error { + var err error + for _, client := range append([]*ethclient.Client{mc.Client}, mc.Backups...) { + err2 := retry.Do(func() error { + err = op(client) + if err != nil { + // TODO: logger? + fmt.Printf("Error %v with client %v\n", err, client) + return err + } + return nil + }, retry.Attempts(mc.RetryConfig.Attempts), retry.Delay(mc.RetryConfig.Delay)) + if err2 == nil { + return nil + } + fmt.Printf("Client %v failed, trying next client\n", client) + } + return errors.Wrapf(err, "All backup clients %v failed", mc.Backups) +} diff --git a/integration-tests/deployment/multiclient_test.go b/integration-tests/deployment/multiclient_test.go new file mode 100644 index 00000000000..a3176691c0c --- /dev/null +++ b/integration-tests/deployment/multiclient_test.go @@ -0,0 +1,36 @@ +package deployment + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMultiClient(t *testing.T) { + // Expect an error if no RPCs supplied. + s := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + writer.WriteHeader(http.StatusOK) + _, err := writer.Write([]byte(`{"jsonrpc":"2.0","id":1,"result":true}`)) + require.NoError(t, err) + })) + defer s.Close() + _, err := NewMultiClient([]RPC{}) + require.Error(t, err) + + // Expect defaults to be set if not provided. + mc, err := NewMultiClient([]RPC{{WSURL: s.URL}}) + require.NoError(t, err) + assert.Equal(t, mc.RetryConfig.Attempts, uint(RPC_DEFAULT_RETRY_ATTEMPTS)) + assert.Equal(t, mc.RetryConfig.Delay, RPC_DEFAULT_RETRY_DELAY) + + // Expect second client to be set as backup. + mc, err = NewMultiClient([]RPC{ + {WSURL: s.URL}, + {WSURL: s.URL}, + }) + require.NoError(t, err) + require.Equal(t, len(mc.Backups), 1) +} diff --git a/integration-tests/go.mod b/integration-tests/go.mod index c8304390a00..d7d460801a3 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -11,6 +11,7 @@ require ( github.com/Khan/genqlient v0.7.0 github.com/Masterminds/semver/v3 v3.2.1 github.com/avast/retry-go/v4 v4.6.0 + github.com/aws/aws-sdk-go v1.45.25 github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df github.com/chaos-mesh/chaos-mesh/api v0.0.0-20240821051457-da69c6d9617a github.com/cli/go-gh/v2 v2.0.0 @@ -107,7 +108,6 @@ require ( 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 From 3a89dceab79217880625f7af75db0d798cf79488 Mon Sep 17 00:00:00 2001 From: Dmytro Haidashenko <34754799+dhaidashenko@users.noreply.github.com> Date: Thu, 19 Sep 2024 19:03:34 +0200 Subject: [PATCH 11/20] use tx in insertLogsWithinTx (#14361) --- .changeset/sixty-cougars-mix.md | 5 +++++ core/chains/evm/logpoller/orm.go | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/sixty-cougars-mix.md diff --git a/.changeset/sixty-cougars-mix.md b/.changeset/sixty-cougars-mix.md new file mode 100644 index 00000000000..a641ce19762 --- /dev/null +++ b/.changeset/sixty-cougars-mix.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Use tx in insertLogsWithinTx #internal diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index 5ab7db4eb02..e40fb80f108 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -390,7 +390,7 @@ func (o *DSORM) insertLogsWithinTx(ctx context.Context, logs []Log, tx sqlutil.D (:evm_chain_id, :log_index, :block_hash, :block_number, :block_timestamp, :address, :event_sig, :topics, :tx_hash, :data, NOW()) ON CONFLICT DO NOTHING` - _, err := o.ds.NamedExecContext(ctx, query, logs[start:end]) + _, err := tx.NamedExecContext(ctx, query, logs[start:end]) if err != nil { if pkgerrors.Is(err, context.DeadlineExceeded) && batchInsertSize > 500 { // In case of DB timeouts, try to insert again with a smaller batch upto a limit From 014a9f51df269d6461ce76c9418ce1977e04e3ac Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Thu, 19 Sep 2024 13:54:38 -0400 Subject: [PATCH 12/20] Fix CCIP Load Test Faulty Fund Return (#14499) * Stop fund return on nil client * DEBUG * Remove debug --- integration-tests/actions/actions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index f864d9e7100..e395c9a251a 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -714,7 +714,7 @@ func TeardownSuite( l.Warn().Msgf("Error deleting jobs %+v", err) } - if chainlinkNodes != nil { + if chainlinkNodes != nil && chainClient != nil { if err := ReturnFundsFromNodes(l, chainClient, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(chainlinkNodes)); err != nil { // This printed line is required for tests that use real funds to propagate the failure // out to the system running the test. Do not remove From 7b324cad8f46ab740ba84c889eca684ed1c87799 Mon Sep 17 00:00:00 2001 From: Domino Valdano Date: Thu, 19 Sep 2024 11:02:10 -0700 Subject: [PATCH 13/20] Fix data race in TestLogPoller_Replay (#14431) * Add RWMutex around global head var * Use atomic.Pointer instead of RWMutex --- .../evm/logpoller/log_poller_internal_test.go | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/core/chains/evm/logpoller/log_poller_internal_test.go b/core/chains/evm/logpoller/log_poller_internal_test.go index 448710b93f3..ca1bd72dd6c 100644 --- a/core/chains/evm/logpoller/log_poller_internal_test.go +++ b/core/chains/evm/logpoller/log_poller_internal_test.go @@ -7,6 +7,7 @@ import ( "math/big" "strings" "sync" + "sync/atomic" "testing" "time" @@ -287,12 +288,14 @@ func TestLogPoller_Replay(t *testing.T) { db := pgtest.NewSqlxDB(t) orm := NewORM(chainID, db, lggr) - head := evmtypes.Head{Number: 4} + var head atomic.Pointer[evmtypes.Head] + head.Store(&evmtypes.Head{Number: 4}) + events := []common.Hash{EmitterABI.Events["Log1"].ID} log1 := types.Log{ Index: 0, BlockHash: common.Hash{}, - BlockNumber: uint64(head.Number), + BlockNumber: uint64(head.Load().Number), Topics: events, Address: addr, TxHash: common.HexToHash("0x1234"), @@ -301,8 +304,7 @@ func TestLogPoller_Replay(t *testing.T) { ec := evmclimocks.NewClient(t) ec.On("HeadByNumber", mock.Anything, mock.Anything).Return(func(context.Context, *big.Int) (*evmtypes.Head, error) { - headCopy := head - return &headCopy, nil + return head.Load(), nil }) ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil).Once() ec.On("ConfiguredChainID").Return(chainID, nil) @@ -318,9 +320,9 @@ func TestLogPoller_Replay(t *testing.T) { headTracker := htMocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) headTracker.On("LatestAndFinalizedBlock", mock.Anything).Return(func(ctx context.Context) (*evmtypes.Head, *evmtypes.Head, error) { - headCopy := head - finalized := &evmtypes.Head{Number: headCopy.Number - lpOpts.FinalityDepth} - return &headCopy, finalized, nil + h := head.Load() + finalized := &evmtypes.Head{Number: h.Number - lpOpts.FinalityDepth} + return h, finalized, nil }) lp := NewLogPoller(orm, ec, lggr, headTracker, lpOpts) @@ -394,7 +396,7 @@ func TestLogPoller_Replay(t *testing.T) { var wg sync.WaitGroup defer func() { wg.Wait() }() ec.On("FilterLogs", mock.Anything, mock.Anything).Once().Return([]types.Log{log1}, nil).Run(func(args mock.Arguments) { - head = evmtypes.Head{Number: 4} + head.Store(&evmtypes.Head{Number: 4}) wg.Add(1) go func() { defer wg.Done() @@ -421,7 +423,7 @@ func TestLogPoller_Replay(t *testing.T) { ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil).Maybe() // in case task gets delayed by >= 100ms - head = evmtypes.Head{Number: 5} + head.Store(&evmtypes.Head{Number: 5}) t.Cleanup(lp.reset) servicetest.Run(t, lp) @@ -448,7 +450,7 @@ func TestLogPoller_Replay(t *testing.T) { go func() { defer close(done) - head = evmtypes.Head{Number: 4} // Restore latest block to 4, so this matches the fromBlock requested + head.Store(&evmtypes.Head{Number: 4}) // Restore latest block to 4, so this matches the fromBlock requested select { case lp.replayStart <- 4: case <-ctx.Done(): @@ -469,7 +471,7 @@ func TestLogPoller_Replay(t *testing.T) { ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil) t.Cleanup(lp.reset) - head = evmtypes.Head{Number: 5} // Latest block must be > lastProcessed in order for SaveAndPollLogs() to call FilterLogs() + head.Store(&evmtypes.Head{Number: 5}) // Latest block must be > lastProcessed in order for SaveAndPollLogs() to call FilterLogs() servicetest.Run(t, lp) select { @@ -482,7 +484,8 @@ func TestLogPoller_Replay(t *testing.T) { // ReplayAsync should return as soon as replayStart is received t.Run("ReplayAsync success", func(t *testing.T) { t.Cleanup(lp.reset) - head = evmtypes.Head{Number: 5} + + head.Store(&evmtypes.Head{Number: 5}) ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil) mockBatchCallContext(t, ec) servicetest.Run(t, lp) @@ -496,7 +499,7 @@ func TestLogPoller_Replay(t *testing.T) { ctx := testutils.Context(t) t.Cleanup(lp.reset) servicetest.Run(t, lp) - head = evmtypes.Head{Number: 4} + head.Store(&evmtypes.Head{Number: 4}) anyErr := pkgerrors.New("async error") observedLogs.TakeAll() @@ -528,7 +531,8 @@ func TestLogPoller_Replay(t *testing.T) { err := lp.orm.DeleteLogsAndBlocksAfter(ctx, 0) require.NoError(t, err) - err = lp.orm.InsertBlock(ctx, head.Hash, head.Number, head.Timestamp, head.Number) + h := head.Load() + err = lp.orm.InsertBlock(ctx, h.Hash, h.Number, h.Timestamp, h.Number) require.NoError(t, err) ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil) From 1e39e3c792086595489b68a22407c471530d4d41 Mon Sep 17 00:00:00 2001 From: ilija42 <57732589+ilija42@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:22:20 +0200 Subject: [PATCH 14/20] [BCFR-198] - Simplify Chain Reader event init (#14493) * Simplify/lint Chain Reader event init * Cleanup ChainReader initDWQuerying to match initTopicQuerying --- core/services/relay/evm/chain_reader.go | 63 ++++++++----------------- 1 file changed, 19 insertions(+), 44 deletions(-) diff --git a/core/services/relay/evm/chain_reader.go b/core/services/relay/evm/chain_reader.go index f4d464f6585..1446d730d74 100644 --- a/core/services/relay/evm/chain_reader.go +++ b/core/services/relay/evm/chain_reader.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "maps" - "reflect" "slices" "strings" "time" @@ -248,10 +247,7 @@ func (cr *chainReader) addEvent(contractName, eventName string, a abi.ABI, chain codecTypes, codecModifiers := make(map[string]types.CodecEntry), make(map[string]commoncodec.Modifier) topicTypeID := codec.WrapItemType(contractName, eventName, true) - codecTypes[topicTypeID], codecModifiers[topicTypeID], err = cr.getEventItemTypeAndModifier(topicTypeID, chainReaderDefinition.InputModifications) - if err != nil { - return err - } + codecTypes[topicTypeID], codecModifiers[topicTypeID] = cr.getEventItemTypeAndModifier(topicTypeID) confirmations, err := ConfirmationsFromConfig(chainReaderDefinition.ConfidenceConfirmations) if err != nil { @@ -299,20 +295,15 @@ func (cr *chainReader) initTopicQuerying(contractName, eventName string, eventIn for topicIndex, topic := range eventInputs { genericTopicName, ok := genericTopicNames[topic.Name] if ok { - // Encoder defs codec won't be used for encoding, but for storing caller filtering params which won't be hashed. - topicTypeID := eventName + "." + genericTopicName - err := cr.addEncoderDef(contractName, topicTypeID, abi.Arguments{{Type: topic.Type}}, nil, inputModifications) - if err != nil { - return nil, nil, nil, err - } + topicsDetails[genericTopicName] = read.TopicDetail{Argument: topic, Index: uint64(topicIndex + 1)} - topicTypeID = codec.WrapItemType(contractName, topicTypeID, true) - topicsTypes[topicTypeID], topicsModifiers[topicTypeID], err = cr.getEventItemTypeAndModifier(topicTypeID, inputModifications) - if err != nil { + topicTypeID := eventName + "." + genericTopicName + if err := cr.addEncoderDef(contractName, topicTypeID, abi.Arguments{{Type: topic.Type}}, nil, inputModifications); err != nil { return nil, nil, nil, err } - topicsDetails[genericTopicName] = read.TopicDetail{Argument: topic, Index: uint64(topicIndex + 1)} + topicCodecTypeID := codec.WrapItemType(contractName, topicTypeID, true) + topicsTypes[topicCodecTypeID], topicsModifiers[topicCodecTypeID] = cr.getEventItemTypeAndModifier(topicCodecTypeID) } } return topicsDetails, topicsTypes, topicsModifiers, nil @@ -324,47 +315,31 @@ func (cr *chainReader) initDWQuerying(contractName, eventName string, eventDWs m dWsDetail := make(map[string]read.DataWordDetail) for genericName, onChainName := range dWDefs { - foundDW := false for _, dWDetail := range eventDWs { - if dWDetail.Name != onChainName { - continue - } + if dWDetail.Name == onChainName { + dWsDetail[genericName] = dWDetail - foundDW = true + dwTypeID := eventName + "." + genericName + if err := cr.addEncoderDef(contractName, dwTypeID, abi.Arguments{abi.Argument{Type: dWDetail.Type}}, nil, nil); err != nil { + return nil, nil, fmt.Errorf("%w: failed to init codec for data word %s on index %d querying for event: %q", err, genericName, dWDetail.Index, eventName) + } - dwTypeID := eventName + "." + genericName - if err := cr.addEncoderDef(contractName, dwTypeID, abi.Arguments{abi.Argument{Type: dWDetail.Type}}, nil, nil); err != nil { - return nil, nil, fmt.Errorf("%w: failed to init codec for data word %s on index %d querying for event: %q", err, genericName, dWDetail.Index, eventName) + dwCodecTypeID := codec.WrapItemType(contractName, dwTypeID, true) + dwsCodecTypeInfo[dwCodecTypeID] = cr.parsed.EncoderDefs[dwCodecTypeID] + break } - - dwCodecTypeID := codec.WrapItemType(contractName, dwTypeID, true) - dwsCodecTypeInfo[dwCodecTypeID] = cr.parsed.EncoderDefs[dwCodecTypeID] - - dWsDetail[genericName] = dWDetail - break } - if !foundDW { - return nil, nil, fmt.Errorf("failed to find data word: %q for event: %q, its either out of bounds or can't be searched for", genericName, eventName) + if _, ok := dWsDetail[genericName]; !ok { + return nil, nil, fmt.Errorf("failed to find data word: %q for event: %q, it either doesn't exist or can't be searched for", genericName, eventName) } } return dWsDetail, dwsCodecTypeInfo, nil } // getEventItemTypeAndModifier returns codec entry for expected incoming event item and the modifier. -func (cr *chainReader) getEventItemTypeAndModifier(itemType string, inputMod commoncodec.ModifiersConfig) (types.CodecEntry, commoncodec.Modifier, error) { +func (cr *chainReader) getEventItemTypeAndModifier(itemType string) (types.CodecEntry, commoncodec.Modifier) { inputTypeInfo := cr.parsed.EncoderDefs[itemType] - // TODO can this be simplified? Isn't this same as inputType.Modifier()? BCI-3909 - inMod, err := inputMod.ToModifier(codec.DecoderHooks...) - if err != nil { - return nil, nil, err - } - - // initialize the modification - if _, err = inMod.RetypeToOffChain(reflect.PointerTo(inputTypeInfo.CheckedType()), ""); err != nil { - return nil, nil, err - } - - return inputTypeInfo, inMod, nil + return inputTypeInfo, inputTypeInfo.Modifier() } func (cr *chainReader) addEncoderDef(contractName, itemType string, args abi.Arguments, prefix []byte, inputModifications commoncodec.ModifiersConfig) error { From 22a8c993ae6ae6ee69626bd239ba2a419fbad450 Mon Sep 17 00:00:00 2001 From: "Abdelrahman Soliman (Boda)" <2677789+asoliman92@users.noreply.github.com> Date: Fri, 20 Sep 2024 18:59:56 +0400 Subject: [PATCH 15/20] Add feed chain deployment test (#14461) * Initial Commit * Add deploy_feed_chain * Refactor deployCapReg to take the chain directly without the selector * Deploy mock link feed * Add merge method to State * Use AddressBook merge * Deploy feed chain in NewEnvironment helper * Move DeployFeeds into test helpers * Add token_info.go token_info facilitates sending tokenConfig to CCIPDeployConfig * go get cl-ccip with reader enabled * wip assert token price reported * make gomodtidy * Change Descriptor to Symbol * fix linting and add changeset * Change Feeds to USDFeeds * Assert token prices by calling FeeQuoter after the commit report * Test token prices in add_chain * bump cl-ccip version * Remove unused code from token_info.go * fix linting * fix linting --- .changeset/young-lions-provide.md | 5 + core/scripts/go.mod | 4 +- core/scripts/go.sum | 8 +- go.mod | 4 +- go.sum | 8 +- .../deployment/ccip/add_chain.go | 15 ++- .../deployment/ccip/add_chain_test.go | 25 ++++- .../deployment/ccip/add_lane_test.go | 2 + .../deployment/ccip/changeset/1_cap_reg.go | 2 +- .../ccip/changeset/2_initial_deploy_test.go | 49 ++++++--- integration-tests/deployment/ccip/consts.go | 10 ++ integration-tests/deployment/ccip/deploy.go | 11 +- .../deployment/ccip/deploy_home_chain.go | 27 +++-- .../deployment/ccip/deploy_test.go | 27 ++++- integration-tests/deployment/ccip/state.go | 41 +++++-- .../deployment/ccip/test_assertions.go | 4 +- .../deployment/ccip/test_helpers.go | 102 ++++++++++++++++-- .../deployment/ccip/token_info.go | 47 ++++++++ integration-tests/go.mod | 4 +- integration-tests/go.sum | 8 +- integration-tests/load/go.mod | 4 +- integration-tests/load/go.sum | 8 +- 22 files changed, 341 insertions(+), 74 deletions(-) create mode 100644 .changeset/young-lions-provide.md create mode 100644 integration-tests/deployment/ccip/consts.go create mode 100644 integration-tests/deployment/ccip/token_info.go diff --git a/.changeset/young-lions-provide.md b/.changeset/young-lions-provide.md new file mode 100644 index 00000000000..45add9558d9 --- /dev/null +++ b/.changeset/young-lions-provide.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#added feed deployment to ccip integration tests diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 720ceec8d12..88388d1c7b2 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -22,7 +22,7 @@ require ( github.com/prometheus/client_golang v1.20.0 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v1.0.4 - github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 + github.com/smartcontractkit/chainlink-common v0.2.3-0.20240919092417-53e784c2e420 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.1 @@ -271,7 +271,7 @@ require ( 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.23 // indirect - github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612 // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20240919174352-8d485ebc0953 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240910155501-42f20443189f // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 6684beddc94..49cba895768 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1081,10 +1081,10 @@ github.com/smartcontractkit/chain-selectors v1.0.23 h1:D2Eaex4Cw/O7Lg3tX6WklOqnj github.com/smartcontractkit/chain-selectors v1.0.23/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-ccip v0.0.0-20240917180332-5a68498d1612 h1:xPEM9XbfZmv8N3NjZ7AX5salonll/LdXrbb8JCbA4FE= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612/go.mod h1:Lv77O13ZxOdmlvnu2vaUC0Lg+t3JAL+N+9K8dRsgmDI= -github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 h1:wqLXuPdiUkn7es/epKmOpB0Q0tKdA9FkYPNQZrZ+VJU= -github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06/go.mod h1:zm+l8gN4LQS1+YvwQDhRz/njirVeWGNiDJKIhCGwaoQ= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240919174352-8d485ebc0953 h1:/Bx9MUUQ+TfS8kIdER8gujpJWfYu8ft4FYzpH8gSPJY= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240919174352-8d485ebc0953/go.mod h1:KP82vFCqm+M1G1t6Vos5CewGUGYJkxxCEdxnta4uLlE= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240919092417-53e784c2e420 h1:+xNnYYgkxzKUIkLCOfzfAKUxeLLtuxlalDI70kNJ8No= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240919092417-53e784c2e420/go.mod h1:zm+l8gN4LQS1+YvwQDhRz/njirVeWGNiDJKIhCGwaoQ= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7/go.mod h1:BMYE1vC/pGmdFSsOJdPrAA0/4gZ0Xo0SxTMdGspBtRo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 h1:yRk4ektpx/UxwarqAfgxUXLrsYXlaNeP1NOwzHGrK2Q= diff --git a/go.mod b/go.mod index 36160f8e96e..4052892209e 100644 --- a/go.mod +++ b/go.mod @@ -74,8 +74,8 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chain-selectors v1.0.23 github.com/smartcontractkit/chainlink-automation v1.0.4 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612 - github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 + github.com/smartcontractkit/chainlink-ccip v0.0.0-20240919174352-8d485ebc0953 + github.com/smartcontractkit/chainlink-common v0.2.3-0.20240919092417-53e784c2e420 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 github.com/smartcontractkit/chainlink-feeds v0.0.0-20240910155501-42f20443189f diff --git a/go.sum b/go.sum index 85fdab94061..75004f3805c 100644 --- a/go.sum +++ b/go.sum @@ -1042,10 +1042,10 @@ github.com/smartcontractkit/chain-selectors v1.0.23 h1:D2Eaex4Cw/O7Lg3tX6WklOqnj github.com/smartcontractkit/chain-selectors v1.0.23/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-ccip v0.0.0-20240917180332-5a68498d1612 h1:xPEM9XbfZmv8N3NjZ7AX5salonll/LdXrbb8JCbA4FE= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612/go.mod h1:Lv77O13ZxOdmlvnu2vaUC0Lg+t3JAL+N+9K8dRsgmDI= -github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 h1:wqLXuPdiUkn7es/epKmOpB0Q0tKdA9FkYPNQZrZ+VJU= -github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06/go.mod h1:zm+l8gN4LQS1+YvwQDhRz/njirVeWGNiDJKIhCGwaoQ= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240919174352-8d485ebc0953 h1:/Bx9MUUQ+TfS8kIdER8gujpJWfYu8ft4FYzpH8gSPJY= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240919174352-8d485ebc0953/go.mod h1:KP82vFCqm+M1G1t6Vos5CewGUGYJkxxCEdxnta4uLlE= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240919092417-53e784c2e420 h1:+xNnYYgkxzKUIkLCOfzfAKUxeLLtuxlalDI70kNJ8No= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240919092417-53e784c2e420/go.mod h1:zm+l8gN4LQS1+YvwQDhRz/njirVeWGNiDJKIhCGwaoQ= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7/go.mod h1:BMYE1vC/pGmdFSsOJdPrAA0/4gZ0Xo0SxTMdGspBtRo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 h1:yRk4ektpx/UxwarqAfgxUXLrsYXlaNeP1NOwzHGrK2Q= diff --git a/integration-tests/deployment/ccip/add_chain.go b/integration-tests/deployment/ccip/add_chain.go index bc997f0dc5e..550d6168a15 100644 --- a/integration-tests/deployment/ccip/add_chain.go +++ b/integration-tests/deployment/ccip/add_chain.go @@ -5,11 +5,15 @@ import ( "github.com/smartcontractkit/ccip-owner-contracts/tools/proposal/mcms" "github.com/smartcontractkit/ccip-owner-contracts/tools/proposal/timelock" + chainsel "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink-ccip/chainconfig" + "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink/integration-tests/deployment" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" @@ -22,8 +26,10 @@ func NewChainInboundProposal( e deployment.Environment, state CCIPOnChainState, homeChainSel uint64, + feedChainSel uint64, newChainSel uint64, sources []uint64, + tokenConfig TokenConfig, ) (*timelock.MCMSWithTimelockProposal, error) { // Generate proposal which enables new destination (from test router) on all source chains. var batches []timelock.BatchChainOperation @@ -118,7 +124,14 @@ func NewChainInboundProposal( return nil, err } - newDONArgs, err := BuildAddDONArgs(e.Logger, state.Chains[newChainSel].OffRamp, e.Chains[newChainSel], nodes.NonBootstraps()) + newDONArgs, err := BuildAddDONArgs( + e.Logger, + state.Chains[newChainSel].OffRamp, + e.Chains[newChainSel], + feedChainSel, + tokenConfig.GetTokenInfo(e.Logger, state.Chains[newChainSel]), + nodes.NonBootstraps(), + ) if err != nil { return nil, err } diff --git a/integration-tests/deployment/ccip/add_chain_test.go b/integration-tests/deployment/ccip/add_chain_test.go index 9441f1a2da6..dbe86b85368 100644 --- a/integration-tests/deployment/ccip/add_chain_test.go +++ b/integration-tests/deployment/ccip/add_chain_test.go @@ -5,12 +5,18 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + + cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/deployment" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -27,9 +33,20 @@ func TestAddChainInbound(t *testing.T) { // We deploy to the rest. initialDeploy := e.Env.AllChainSelectorsExcluding([]uint64{newChain}) + feeds := state.Chains[e.FeedChainSel].USDFeeds + tokenConfig := NewTokenConfig() + tokenConfig.UpsertTokenInfo(LinkSymbol, + pluginconfig.TokenInfo{ + AggregatorAddress: feeds[LinkSymbol].Address().String(), + Decimals: LinkDecimals, + DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), + }, + ) ab, err := DeployCCIPContracts(e.Env, DeployCCIPContractConfig{ HomeChainSel: e.HomeChainSel, + FeedChainSel: e.FeedChainSel, ChainsToDeploy: initialDeploy, + TokenConfig: tokenConfig, CCIPOnChainState: state, }) require.NoError(t, err) @@ -103,7 +120,7 @@ func TestAddChainInbound(t *testing.T) { require.Equal(t, state.Chains[e.HomeChainSel].Timelock.Address(), crOwner) // Generate and sign inbound proposal to new 4th chain. - chainInboundProposal, err := NewChainInboundProposal(e.Env, state, e.HomeChainSel, newChain, initialDeploy) + chainInboundProposal, err := NewChainInboundProposal(e.Env, state, e.HomeChainSel, e.FeedChainSel, newChain, initialDeploy, tokenConfig) require.NoError(t, err) chainInboundExec := SignProposal(t, e.Env, chainInboundProposal) for _, sel := range initialDeploy { @@ -160,4 +177,10 @@ func TestAddChainInbound(t *testing.T) { seqNr := SendRequest(t, e.Env, state, initialDeploy[0], newChain, true) require.NoError(t, ConfirmExecWithSeqNr(t, e.Env.Chains[initialDeploy[0]], e.Env.Chains[newChain], state.Chains[newChain].OffRamp, &startBlock, seqNr)) + + linkAddress := state.Chains[newChain].LinkToken.Address() + feeQuoter := state.Chains[newChain].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, MockLinkPrice, timestampedPrice.Value) } diff --git a/integration-tests/deployment/ccip/add_lane_test.go b/integration-tests/deployment/ccip/add_lane_test.go index d43526d8d49..3da74ec11a8 100644 --- a/integration-tests/deployment/ccip/add_lane_test.go +++ b/integration-tests/deployment/ccip/add_lane_test.go @@ -23,6 +23,8 @@ func TestAddLane(t *testing.T) { // Set up CCIP contracts and a DON per chain. ab, err := DeployCCIPContracts(e.Env, DeployCCIPContractConfig{ HomeChainSel: e.HomeChainSel, + FeedChainSel: e.FeedChainSel, + TokenConfig: NewTokenConfig(), CCIPOnChainState: state, }) require.NoError(t, err) diff --git a/integration-tests/deployment/ccip/changeset/1_cap_reg.go b/integration-tests/deployment/ccip/changeset/1_cap_reg.go index 58634916235..90c1a94fe8d 100644 --- a/integration-tests/deployment/ccip/changeset/1_cap_reg.go +++ b/integration-tests/deployment/ccip/changeset/1_cap_reg.go @@ -10,7 +10,7 @@ import ( // Separate migration because cap reg is an env var for CL nodes. func Apply0001(env deployment.Environment, homeChainSel uint64) (deployment.ChangesetOutput, error) { // Note we also deploy the cap reg. - ab, _, err := ccipdeployment.DeployCapReg(env.Logger, env.Chains, homeChainSel) + ab, _, err := ccipdeployment.DeployCapReg(env.Logger, env.Chains[homeChainSel]) if err != nil { env.Logger.Errorw("Failed to deploy cap reg", "err", err, "addresses", ab) return deployment.ChangesetOutput{}, err diff --git a/integration-tests/deployment/ccip/changeset/2_initial_deploy_test.go b/integration-tests/deployment/ccip/changeset/2_initial_deploy_test.go index 90a8627f38d..8dc363b0cbb 100644 --- a/integration-tests/deployment/ccip/changeset/2_initial_deploy_test.go +++ b/integration-tests/deployment/ccip/changeset/2_initial_deploy_test.go @@ -3,40 +3,56 @@ package changeset import ( "testing" + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + + cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" + "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" - ccipdeployment "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip" + ccdeploy "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip" jobv1 "github.com/smartcontractkit/chainlink/integration-tests/deployment/jd/job/v1" + "github.com/smartcontractkit/chainlink/v2/core/logger" ) func Test0002_InitialDeploy(t *testing.T) { lggr := logger.TestLogger(t) - ctx := ccipdeployment.Context(t) - tenv := ccipdeployment.NewEnvironmentWithCR(t, lggr, 3) + ctx := ccdeploy.Context(t) + tenv := ccdeploy.NewEnvironmentWithCRAndFeeds(t, lggr, 3) e := tenv.Env nodes := tenv.Nodes chains := e.Chains - state, err := ccipdeployment.LoadOnchainState(tenv.Env, tenv.Ab) + state, err := ccdeploy.LoadOnchainState(tenv.Env, tenv.Ab) require.NoError(t, err) + feeds := state.Chains[tenv.FeedChainSel].USDFeeds + tokenConfig := ccdeploy.NewTokenConfig() + tokenConfig.UpsertTokenInfo(ccdeploy.LinkSymbol, + pluginconfig.TokenInfo{ + AggregatorAddress: feeds[ccdeploy.LinkSymbol].Address().String(), + Decimals: ccdeploy.LinkDecimals, + DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), + }, + ) // Apply migration - output, err := Apply0002(tenv.Env, ccipdeployment.DeployCCIPContractConfig{ + output, err := Apply0002(tenv.Env, ccdeploy.DeployCCIPContractConfig{ HomeChainSel: tenv.HomeChainSel, + FeedChainSel: tenv.FeedChainSel, ChainsToDeploy: tenv.Env.AllChainSelectors(), - // Capreg/config already exist. + TokenConfig: tokenConfig, + // Capreg/config and feeds already exist. CCIPOnChainState: state, }) require.NoError(t, err) // Get new state after migration. - state, err = ccipdeployment.LoadOnchainState(e, output.AddressBook) + state, err = ccdeploy.LoadOnchainState(e, output.AddressBook) require.NoError(t, err) // Ensure capreg logs are up to date. - require.NoError(t, ccipdeployment.ReplayAllLogs(nodes, chains)) + require.NoError(t, ccdeploy.ReplayAllLogs(nodes, chains)) // Apply the jobs. for nodeID, jobs := range output.JobSpecs { @@ -52,7 +68,7 @@ func Test0002_InitialDeploy(t *testing.T) { } // Add all lanes - require.NoError(t, ccipdeployment.AddLanesForAll(e, state)) + require.NoError(t, ccdeploy.AddLanesForAll(e, state)) // Need to keep track of the block number for each chain so that event subscription can be done from that block. startBlocks := make(map[uint64]*uint64) // Send a message from each chain to every other chain. @@ -66,16 +82,25 @@ func Test0002_InitialDeploy(t *testing.T) { require.NoError(t, err) block := latesthdr.Number.Uint64() startBlocks[dest] = &block - seqNum := ccipdeployment.SendRequest(t, e, state, src, dest, false) + seqNum := ccdeploy.SendRequest(t, e, state, src, dest, false) expectedSeqNum[dest] = seqNum } } // Wait for all commit reports to land. - ccipdeployment.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + for dest := range e.Chains { + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, ccdeploy.MockLinkPrice, timestampedPrice.Value) + } // Wait for all exec reports to land - ccipdeployment.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) // TODO: Apply the proposal. } diff --git a/integration-tests/deployment/ccip/consts.go b/integration-tests/deployment/ccip/consts.go new file mode 100644 index 00000000000..e9b7a9f2cec --- /dev/null +++ b/integration-tests/deployment/ccip/consts.go @@ -0,0 +1,10 @@ +package ccipdeployment + +type TokenSymbol string + +const ( + LinkSymbol TokenSymbol = "LINK" + WethSymbol TokenSymbol = "WETH" + LinkDecimals = 18 + WethDecimals = 18 +) diff --git a/integration-tests/deployment/ccip/deploy.go b/integration-tests/deployment/ccip/deploy.go index dab50f58205..f0641b65165 100644 --- a/integration-tests/deployment/ccip/deploy.go +++ b/integration-tests/deployment/ccip/deploy.go @@ -10,12 +10,14 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/smartcontractkit/ccip-owner-contracts/tools/configwrappers" owner_helpers "github.com/smartcontractkit/ccip-owner-contracts/tools/gethwrappers" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface" "github.com/smartcontractkit/chainlink/integration-tests/deployment" @@ -48,6 +50,7 @@ var ( OnRamp deployment.ContractType = "OnRamp" OffRamp deployment.ContractType = "OffRamp" CapabilitiesRegistry deployment.ContractType = "CapabilitiesRegistry" + PriceFeed deployment.ContractType = "PriceFeed" // Note test router maps to a regular router contract. TestRouter deployment.ContractType = "TestRouter" CCIPReceiver deployment.ContractType = "CCIPReceiver" @@ -78,7 +81,8 @@ type Contracts interface { *offramp.OffRamp | *onramp.OnRamp | *burn_mint_erc677.BurnMintERC677 | - *maybe_revert_message_receiver.MaybeRevertMessageReceiver + *maybe_revert_message_receiver.MaybeRevertMessageReceiver | + *aggregator_v3_interface.AggregatorV3Interface } type ContractDeploy[C Contracts] struct { @@ -119,7 +123,9 @@ func deployContract[C Contracts]( type DeployCCIPContractConfig struct { HomeChainSel uint64 + FeedChainSel uint64 ChainsToDeploy []uint64 + TokenConfig TokenConfig // Existing contracts which we want to skip deployment // Leave empty if we want to deploy everything // TODO: Add skips to deploy function. @@ -178,6 +184,7 @@ func DeployCCIPContracts(e deployment.Environment, c DeployCCIPContractConfig) ( return ab, err } + tokenInfo := c.TokenConfig.GetTokenInfo(e.Logger, chainState) // TODO: Do we want to extract this? // Add chain config for each chain. _, err = AddChainConfig( @@ -196,6 +203,8 @@ func DeployCCIPContracts(e deployment.Environment, c DeployCCIPContractConfig) ( c.Chains[c.HomeChainSel].CapabilityRegistry, c.Chains[c.HomeChainSel].CCIPConfig, chainState.OffRamp, + c.FeedChainSel, + tokenInfo, chain, e.Chains[c.HomeChainSel], nodes.NonBootstraps(), diff --git a/integration-tests/deployment/ccip/deploy_home_chain.go b/integration-tests/deployment/ccip/deploy_home_chain.go index 94da977d6c1..c9d3814a672 100644 --- a/integration-tests/deployment/ccip/deploy_home_chain.go +++ b/integration-tests/deployment/ccip/deploy_home_chain.go @@ -9,17 +9,20 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "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/logger" "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" + confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink/integration-tests/deployment" + cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" @@ -67,9 +70,8 @@ func MustABIEncode(abiString string, args ...interface{}) []byte { return encoded } -func DeployCapReg(lggr logger.Logger, chains map[uint64]deployment.Chain, chainSel uint64) (deployment.AddressBook, common.Address, error) { +func DeployCapReg(lggr logger.Logger, chain deployment.Chain) (deployment.AddressBook, common.Address, error) { ab := deployment.NewMemoryAddressBook() - chain := chains[chainSel] capReg, err := deployContract(lggr, chain, ab, func(chain deployment.Chain) ContractDeploy[*capabilities_registry.CapabilitiesRegistry] { crAddr, tx, cr, err2 := capabilities_registry.DeployCapabilitiesRegistry( @@ -196,6 +198,9 @@ func BuildAddDONArgs( lggr logger.Logger, offRamp *offramp.OffRamp, dest deployment.Chain, + feedChainSel uint64, + // Token address on Dest chain to aggregate address on feed chain + tokenInfo map[ocrtypes.Account]pluginconfig.TokenInfo, nodes deployment.Nodes, ) ([]byte, error) { p2pIDs := nodes.PeerIDs() @@ -229,11 +234,8 @@ func BuildAddDONArgs( encodedOffchainConfig, err2 = pluginconfig.EncodeCommitOffchainConfig(pluginconfig.CommitOffchainConfig{ RemoteGasPriceBatchWriteFrequency: *commonconfig.MustNewDuration(RemoteGasPriceBatchWriteFrequency), TokenPriceBatchWriteFrequency: *commonconfig.MustNewDuration(TokenPriceBatchWriteFrequency), - // TODO: Use a specific feed chain - // Use homechain as the feed chain to simplify testing - TokenInfo: map[ocrtypes.Account]pluginconfig.TokenInfo{ - //TODO: Add remote chain tokens as keys with their respective aggregate contract on feedChain - }, + PriceFeedChainSelector: ccipocr3.ChainSelector(feedChainSel), + TokenInfo: tokenInfo, }) } else { encodedOffchainConfig, err2 = pluginconfig.EncodeExecuteOffchainConfig(pluginconfig.ExecuteOffchainConfig{ @@ -367,11 +369,14 @@ func AddDON( capReg *capabilities_registry.CapabilitiesRegistry, ccipConfig *ccip_config.CCIPConfig, offRamp *offramp.OffRamp, + feedChainSel uint64, + // Token address on Dest chain to aggregate address on feed chain + tokenInfo map[ocrtypes.Account]pluginconfig.TokenInfo, dest deployment.Chain, home deployment.Chain, nodes deployment.Nodes, ) error { - encodedConfigs, err := BuildAddDONArgs(lggr, offRamp, dest, nodes) + encodedConfigs, err := BuildAddDONArgs(lggr, offRamp, dest, feedChainSel, tokenInfo, nodes) if err != nil { return err } diff --git a/integration-tests/deployment/ccip/deploy_test.go b/integration-tests/deployment/ccip/deploy_test.go index e2963b84a3b..db739f64134 100644 --- a/integration-tests/deployment/ccip/deploy_test.go +++ b/integration-tests/deployment/ccip/deploy_test.go @@ -17,19 +17,36 @@ func TestDeployCCIPContracts(t *testing.T) { lggr := logger.TestLogger(t) e := memory.NewMemoryEnvironment(t, lggr, zapcore.InfoLevel, memory.MemoryEnvironmentConfig{ Bootstraps: 1, - Chains: 1, + Chains: 2, Nodes: 4, }) // Deploy all the CCIP contracts. - homeChain := e.AllChainSelectors()[0] - capRegAddresses, _, err := DeployCapReg(lggr, e.Chains, homeChain) + homeChain := e.AllChainSelectors()[HomeChainIndex] + addressBook, _, err := DeployCapReg(lggr, e.Chains[homeChain]) require.NoError(t, err) - s, err := LoadOnchainState(e, capRegAddresses) + s, err := LoadOnchainState(e, addressBook) require.NoError(t, err) + + feedChain := e.AllChainSelectors()[FeedChainIndex] + feedAddresses, _, err := DeployFeeds(lggr, e.Chains[feedChain]) + require.NoError(t, err) + + // Merge the feed addresses into the address book. + require.NoError(t, addressBook.Merge(feedAddresses)) + + // Load the state after deploying the cap reg and feeds. + homeAndFeedStates, err := LoadOnchainState(e, addressBook) + require.NoError(t, err) + require.NotNil(t, s.Chains[homeChain].CapabilityRegistry) + require.NotNil(t, s.Chains[homeChain].CCIPConfig) + require.NotNil(t, homeAndFeedStates.Chains[feedChain].USDFeeds) + ab, err := DeployCCIPContracts(e, DeployCCIPContractConfig{ HomeChainSel: homeChain, + FeedChainSel: feedChain, ChainsToDeploy: e.AllChainSelectors(), - CCIPOnChainState: s, + TokenConfig: NewTokenConfig(), + CCIPOnChainState: homeAndFeedStates, }) require.NoError(t, err) state, err := LoadOnchainState(e, ab) diff --git a/integration-tests/deployment/ccip/state.go b/integration-tests/deployment/ccip/state.go index 50ed396d9d8..d32c51ae65f 100644 --- a/integration-tests/deployment/ccip/state.go +++ b/integration-tests/deployment/ccip/state.go @@ -3,19 +3,19 @@ package ccipdeployment import ( "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + chainsel "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink/integration-tests/deployment" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/maybe_revert_message_receiver" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" owner_wrappers "github.com/smartcontractkit/ccip-owner-contracts/tools/gethwrappers" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/maybe_revert_message_receiver" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/nonce_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" @@ -24,6 +24,9 @@ import ( "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/aggregator_v3_interface" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" ) type CCIPChainState struct { @@ -38,6 +41,15 @@ type CCIPChainState struct { RMNRemote *rmn_remote.RMNRemote // TODO: May need to support older link too LinkToken *burn_mint_erc677.BurnMintERC677 + // Map between token Descriptor (e.g. LinkSymbol, WethSymbol) + // and the respective token contract + // This is more of an illustration of how we'll have tokens, and it might need some work later to work properly. + // Not all tokens will be burn and mint tokens. + BurnMintTokens677 map[TokenSymbol]*burn_mint_erc677.BurnMintERC677 + // Map between token Symbol (e.g. LinkSymbol, WethSymbol) + // and the respective aggregator USD feed contract + USDFeeds map[TokenSymbol]*aggregator_v3_interface.AggregatorV3Interface + // Note we only expect one of these (on the home chain) CapabilityRegistry *capabilities_registry.CapabilitiesRegistry CCIPConfig *ccip_config.CCIPConfig @@ -188,7 +200,7 @@ func LoadOnchainState(e deployment.Environment, ab deployment.AddressBook) (CCIP return state, nil } -// Loads all state for a chain into state +// LoadChainState Loads all state for a chain into state // Modifies map in place func LoadChainState(chain deployment.Chain, addresses map[string]deployment.TypeAndVersion) (CCIPChainState, error) { var state CCIPChainState @@ -290,6 +302,23 @@ func LoadChainState(chain deployment.Chain, addresses map[string]deployment.Type return state, err } state.Receiver = mr + case deployment.NewTypeAndVersion(PriceFeed, deployment.Version1_0_0).String(): + feed, err := aggregator_v3_interface.NewAggregatorV3Interface(common.HexToAddress(address), chain.Client) + if err != nil { + return state, err + } + if state.USDFeeds == nil { + state.USDFeeds = make(map[TokenSymbol]*aggregator_v3_interface.AggregatorV3Interface) + } + desc, err := feed.Description(&bind.CallOpts{}) + if err != nil { + return state, err + } + key, ok := MockDescriptionToTokenSymbol[desc] + if !ok { + return state, fmt.Errorf("unknown feed description %s", desc) + } + state.USDFeeds[key] = feed default: return state, fmt.Errorf("unknown contract %s", tvStr) } diff --git a/integration-tests/deployment/ccip/test_assertions.go b/integration-tests/deployment/ccip/test_assertions.go index 02a10fff3e6..256d4bf8b62 100644 --- a/integration-tests/deployment/ccip/test_assertions.go +++ b/integration-tests/deployment/ccip/test_assertions.go @@ -115,8 +115,8 @@ func ConfirmCommitWithExpectedSeqNumRange( if mr.SourceChainSelector == src.Selector && uint64(expectedSeqNumRange.Start()) == mr.MinSeqNr && uint64(expectedSeqNumRange.End()) == mr.MaxSeqNr { - t.Logf("Received commit report on selector %d from source selector %d expected seq nr range %s", - dest.Selector, src.Selector, expectedSeqNumRange.String()) + t.Logf("Received commit report on selector %d from source selector %d expected seq nr range %s, token prices: %v", + dest.Selector, src.Selector, expectedSeqNumRange.String(), report.Report.PriceUpdates.TokenPriceUpdates) return nil } } diff --git a/integration-tests/deployment/ccip/test_helpers.go b/integration-tests/deployment/ccip/test_helpers.go index 330cbae1964..8f7a7b6c90e 100644 --- a/integration-tests/deployment/ccip/test_helpers.go +++ b/integration-tests/deployment/ccip/test_helpers.go @@ -2,6 +2,8 @@ package ccipdeployment import ( "context" + "fmt" + "math/big" "sort" "testing" "time" @@ -11,19 +13,29 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/logging" "github.com/ethereum/go-ethereum/common" - chainsel "github.com/smartcontractkit/chain-selectors" "github.com/stretchr/testify/require" + + "go.uber.org/multierr" "go.uber.org/zap/zapcore" - jobv1 "github.com/smartcontractkit/chainlink/integration-tests/deployment/jd/job/v1" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" + chainsel "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink/integration-tests/deployment" + jobv1 "github.com/smartcontractkit/chainlink/integration-tests/deployment/jd/job/v1" "github.com/smartcontractkit/chainlink/integration-tests/deployment/memory" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/integration-tests/deployment/devenv" + + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_v3_aggregator_contract" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface" +) + +const ( + HomeChainIndex = 0 + FeedChainIndex = 1 ) // Context returns a context with the test's deadline, if available. @@ -47,12 +59,14 @@ type DeployedTestEnvironment struct { Ab deployment.AddressBook Env deployment.Environment HomeChainSel uint64 + FeedChainSel uint64 Nodes map[string]memory.Node } -// NewDeployedEnvironment creates a new CCIP environment -// with capreg and nodes set up. -func NewEnvironmentWithCR(t *testing.T, lggr logger.Logger, numChains int) DeployedTestEnvironment { +// NewEnvironmentWithCRAndFeeds creates a new CCIP environment +// with capreg, feeds and nodes set up. +func NewEnvironmentWithCRAndFeeds(t *testing.T, lggr logger.Logger, numChains int) DeployedTestEnvironment { + require.GreaterOrEqual(t, numChains, 2, "numChains must be at least 2 for home and feed chains") ctx := Context(t) chains := memory.NewMemoryChains(t, numChains) // Lower chainSel is home chain. @@ -65,10 +79,15 @@ func NewEnvironmentWithCR(t *testing.T, lggr logger.Logger, numChains int) Deplo return chainSels[i] < chainSels[j] }) // Take lowest for determinism. - homeChainSel := chainSels[0] + homeChainSel := chainSels[HomeChainIndex] homeChainEVM, _ := chainsel.ChainIdFromSelector(homeChainSel) - ab, capReg, err := DeployCapReg(lggr, chains, homeChainSel) + ab, capReg, err := DeployCapReg(lggr, chains[homeChainSel]) + require.NoError(t, err) + + feedSel := chainSels[FeedChainIndex] + feedAb, _, err := DeployFeeds(lggr, chains[feedSel]) require.NoError(t, err) + require.NoError(t, ab.Merge(feedAb)) nodes := memory.NewNodes(t, zapcore.InfoLevel, chains, 4, 1, deployment.CapabilityRegistryConfig{ EVMChainID: homeChainEVM, @@ -86,13 +105,14 @@ func NewEnvironmentWithCR(t *testing.T, lggr logger.Logger, numChains int) Deplo Ab: ab, Env: e, HomeChainSel: homeChainSel, + FeedChainSel: feedSel, Nodes: nodes, } } func NewEnvironmentWithCRAndJobs(t *testing.T, lggr logger.Logger, numChains int) DeployedTestEnvironment { ctx := Context(t) - e := NewEnvironmentWithCR(t, lggr, numChains) + e := NewEnvironmentWithCRAndFeeds(t, lggr, numChains) jbs, err := NewCCIPJobSpecs(e.Env.NodeIDs, e.Env.Offchain) require.NoError(t, err) for nodeID, jobs := range jbs { @@ -191,7 +211,7 @@ func NewDeployedLocalDevEnvironment(t *testing.T, lggr logger.Logger) DeployedLo require.NotEmpty(t, homeChainEVM, "homeChainEVM should not be empty") // deploy the capability registry - ab, capReg, err := DeployCapReg(lggr, chains, homeChainSel) + ab, capReg, err := DeployCapReg(lggr, chains[homeChainSel]) require.NoError(t, err) // start the chainlink nodes with the CR address @@ -233,3 +253,65 @@ func AddLanesForAll(e deployment.Environment, state CCIPOnChainState) error { } return nil } + +const ( + // MockLinkAggregatorDescription This is the description of the MockV3Aggregator.sol contract + // nolint:lll + // https://github.com/smartcontractkit/chainlink/blob/a348b98e90527520049c580000a86fb8ceff7fa7/contracts/src/v0.8/tests/MockV3Aggregator.sol#L76-L76 + MockLinkAggregatorDescription = "v0.8/tests/MockV3Aggregator.sol" + // MockWETHAggregatorDescription WETH use description from MockETHUSDAggregator.sol + // nolint:lll + // https://github.com/smartcontractkit/chainlink/blob/a348b98e90527520049c580000a86fb8ceff7fa7/contracts/src/v0.8/automation/testhelpers/MockETHUSDAggregator.sol#L19-L19 + MockWETHAggregatorDescription = "MockETHUSDAggregator" +) + +var ( + MockLinkPrice = big.NewInt(5e18) + // MockDescriptionToTokenSymbol maps a mock feed description to token descriptor + MockDescriptionToTokenSymbol = map[string]TokenSymbol{ + MockLinkAggregatorDescription: LinkSymbol, + MockWETHAggregatorDescription: WethSymbol, + } +) + +func DeployFeeds(lggr logger.Logger, chain deployment.Chain) (deployment.AddressBook, map[string]common.Address, error) { + ab := deployment.NewMemoryAddressBook() + linkTV := deployment.NewTypeAndVersion(PriceFeed, deployment.Version1_0_0) + mockLinkFeed, err := deployContract(lggr, chain, ab, + func(chain deployment.Chain) ContractDeploy[*aggregator_v3_interface.AggregatorV3Interface] { + linkFeed, tx, _, err1 := mock_v3_aggregator_contract.DeployMockV3Aggregator( + chain.DeployerKey, + chain.Client, + LinkDecimals, // decimals + MockLinkPrice, // initialAnswer + ) + aggregatorCr, err2 := aggregator_v3_interface.NewAggregatorV3Interface(linkFeed, chain.Client) + + return ContractDeploy[*aggregator_v3_interface.AggregatorV3Interface]{ + Address: linkFeed, Contract: aggregatorCr, Tv: linkTV, Tx: tx, Err: multierr.Append(err1, err2), + } + }) + + if err != nil { + lggr.Errorw("Failed to deploy link feed", "err", err) + return ab, nil, err + } + + lggr.Infow("deployed mockLinkFeed", "addr", mockLinkFeed.Address) + + desc, err := mockLinkFeed.Contract.Description(&bind.CallOpts{}) + if err != nil { + lggr.Errorw("Failed to get description", "err", err) + return ab, nil, err + } + + if desc != MockLinkAggregatorDescription { + lggr.Errorw("Unexpected description for Link token", "desc", desc) + return ab, nil, fmt.Errorf("unexpected description: %s", desc) + } + + tvToAddress := map[string]common.Address{ + desc: mockLinkFeed.Address, + } + return ab, tvToAddress, nil +} diff --git a/integration-tests/deployment/ccip/token_info.go b/integration-tests/deployment/ccip/token_info.go new file mode 100644 index 00000000000..1ea09949bc4 --- /dev/null +++ b/integration-tests/deployment/ccip/token_info.go @@ -0,0 +1,47 @@ +package ccipdeployment + +import ( + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +// TokenConfig mapping between token Symbol (e.g. LinkSymbol, WethSymbol) +// and the respective token info. +type TokenConfig struct { + TokenSymbolToInfo map[TokenSymbol]pluginconfig.TokenInfo +} + +func NewTokenConfig() TokenConfig { + return TokenConfig{ + TokenSymbolToInfo: make(map[TokenSymbol]pluginconfig.TokenInfo), + } +} + +func (tc *TokenConfig) UpsertTokenInfo( + symbol TokenSymbol, + info pluginconfig.TokenInfo, +) { + tc.TokenSymbolToInfo[symbol] = info +} + +// GetTokenInfo Adds mapping between dest chain tokens and their respective aggregators on feed chain. +func (tc *TokenConfig) GetTokenInfo( + lggr logger.Logger, + destState CCIPChainState, +) map[ocrtypes.Account]pluginconfig.TokenInfo { + tokenToAggregate := make(map[ocrtypes.Account]pluginconfig.TokenInfo) + if _, ok := tc.TokenSymbolToInfo[LinkSymbol]; !ok { + lggr.Debugw("Link aggregator not found, deploy without mapping link token") + } else { + lggr.Debugw("Mapping LinkToken to Link aggregator") + acc := ocrtypes.Account(destState.LinkToken.Address().String()) + tokenToAggregate[acc] = tc.TokenSymbolToInfo[LinkSymbol] + } + + // TODO: Populate tokenInfo with weth and the token map in destState + + return tokenToAggregate +} diff --git a/integration-tests/go.mod b/integration-tests/go.mod index d7d460801a3..e673e559bc1 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -39,8 +39,8 @@ require ( github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240910151738-3f318badcfb5 github.com/smartcontractkit/chain-selectors v1.0.23 github.com/smartcontractkit/chainlink-automation v1.0.4 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612 - github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 + github.com/smartcontractkit/chainlink-ccip v0.0.0-20240919174352-8d485ebc0953 + github.com/smartcontractkit/chainlink-common v0.2.3-0.20240919092417-53e784c2e420 github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.0 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.6 github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 20a28e1dfbe..ee802182c1a 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1423,10 +1423,10 @@ github.com/smartcontractkit/chain-selectors v1.0.23 h1:D2Eaex4Cw/O7Lg3tX6WklOqnj github.com/smartcontractkit/chain-selectors v1.0.23/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-ccip v0.0.0-20240917180332-5a68498d1612 h1:xPEM9XbfZmv8N3NjZ7AX5salonll/LdXrbb8JCbA4FE= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612/go.mod h1:Lv77O13ZxOdmlvnu2vaUC0Lg+t3JAL+N+9K8dRsgmDI= -github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 h1:wqLXuPdiUkn7es/epKmOpB0Q0tKdA9FkYPNQZrZ+VJU= -github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06/go.mod h1:zm+l8gN4LQS1+YvwQDhRz/njirVeWGNiDJKIhCGwaoQ= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240919174352-8d485ebc0953 h1:/Bx9MUUQ+TfS8kIdER8gujpJWfYu8ft4FYzpH8gSPJY= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240919174352-8d485ebc0953/go.mod h1:KP82vFCqm+M1G1t6Vos5CewGUGYJkxxCEdxnta4uLlE= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240919092417-53e784c2e420 h1:+xNnYYgkxzKUIkLCOfzfAKUxeLLtuxlalDI70kNJ8No= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240919092417-53e784c2e420/go.mod h1:zm+l8gN4LQS1+YvwQDhRz/njirVeWGNiDJKIhCGwaoQ= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7/go.mod h1:BMYE1vC/pGmdFSsOJdPrAA0/4gZ0Xo0SxTMdGspBtRo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 h1:yRk4ektpx/UxwarqAfgxUXLrsYXlaNeP1NOwzHGrK2Q= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 67d2bb65095..90eeea63f43 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -15,7 +15,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.33.0 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 + github.com/smartcontractkit/chainlink-common v0.2.3-0.20240919092417-53e784c2e420 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.6 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.1 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.0 @@ -386,7 +386,7 @@ require ( github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/chain-selectors v1.0.23 // indirect - github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612 // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20240919174352-8d485ebc0953 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240910155501-42f20443189f // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 0954d5afd70..37fa4cadda8 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1397,10 +1397,10 @@ github.com/smartcontractkit/chain-selectors v1.0.23 h1:D2Eaex4Cw/O7Lg3tX6WklOqnj github.com/smartcontractkit/chain-selectors v1.0.23/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-ccip v0.0.0-20240917180332-5a68498d1612 h1:xPEM9XbfZmv8N3NjZ7AX5salonll/LdXrbb8JCbA4FE= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240917180332-5a68498d1612/go.mod h1:Lv77O13ZxOdmlvnu2vaUC0Lg+t3JAL+N+9K8dRsgmDI= -github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06 h1:wqLXuPdiUkn7es/epKmOpB0Q0tKdA9FkYPNQZrZ+VJU= -github.com/smartcontractkit/chainlink-common v0.2.3-0.20240918210534-564164004d06/go.mod h1:zm+l8gN4LQS1+YvwQDhRz/njirVeWGNiDJKIhCGwaoQ= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240919174352-8d485ebc0953 h1:/Bx9MUUQ+TfS8kIdER8gujpJWfYu8ft4FYzpH8gSPJY= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240919174352-8d485ebc0953/go.mod h1:KP82vFCqm+M1G1t6Vos5CewGUGYJkxxCEdxnta4uLlE= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240919092417-53e784c2e420 h1:+xNnYYgkxzKUIkLCOfzfAKUxeLLtuxlalDI70kNJ8No= +github.com/smartcontractkit/chainlink-common v0.2.3-0.20240919092417-53e784c2e420/go.mod h1:zm+l8gN4LQS1+YvwQDhRz/njirVeWGNiDJKIhCGwaoQ= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7/go.mod h1:BMYE1vC/pGmdFSsOJdPrAA0/4gZ0Xo0SxTMdGspBtRo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 h1:yRk4ektpx/UxwarqAfgxUXLrsYXlaNeP1NOwzHGrK2Q= From d2d9568318abe0ce88bc12a1308e0e96131b0223 Mon Sep 17 00:00:00 2001 From: martin-cll <121895364+martin-cll@users.noreply.github.com> Date: Sat, 21 Sep 2024 02:18:56 +1000 Subject: [PATCH 16/20] MERC-6299 Skip telemetry for market status bridges (#14415) * Skip telemetry for market status bridges * Update changeset * Remove field --- .changeset/slow-lizards-shout.md | 5 + core/services/ocrcommon/telemetry.go | 45 ++++-- core/services/ocrcommon/telemetry_test.go | 142 +++++++++++++++++- .../telem/telem_enhanced_ea_mercury.pb.go | 2 +- .../telem/telem_enhanced_ea_mercury.proto | 2 +- 5 files changed, 174 insertions(+), 22 deletions(-) create mode 100644 .changeset/slow-lizards-shout.md diff --git a/.changeset/slow-lizards-shout.md b/.changeset/slow-lizards-shout.md new file mode 100644 index 00000000000..3b21c6576e7 --- /dev/null +++ b/.changeset/slow-lizards-shout.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Skip telemetry for market-status bridges #internal diff --git a/core/services/ocrcommon/telemetry.go b/core/services/ocrcommon/telemetry.go index f146bacc181..810952f455e 100644 --- a/core/services/ocrcommon/telemetry.go +++ b/core/services/ocrcommon/telemetry.go @@ -174,7 +174,14 @@ func ParseMercuryEATelemetry(lggr logger.Logger, trrs pipeline.TaskRunResults, f eaTelem.BridgeTaskRunStartedTimestamp = trr.CreatedAt.UnixMilli() eaTelem.BridgeTaskRunEndedTimestamp = trr.FinishedAt.Time.UnixMilli() - eaTelem.AssetSymbol = getAssetSymbolFromRequestData(bridgeTask.RequestData) + + parsedBridgeData := parseBridgeRequestData(bridgeTask.RequestData, feedVersion) + if parsedBridgeData.IsMarketStatus { + // Only collect telemetry for pricing bridges. + continue + } + + eaTelem.AssetSymbol = parsedBridgeData.AssetSymbol eaTelemetryValues = append(eaTelemetryValues, eaTelem) } @@ -477,12 +484,19 @@ func parseTelemetryAttributes(a string) (telemetryAttributes, error) { return *attrs, nil } -// getAssetSymbolFromRequestData parses the requestData of the bridge to generate an asset symbol pair -func getAssetSymbolFromRequestData(requestData string) string { +type bridgeRequestData struct { + AssetSymbol string + IsMarketStatus bool +} + +// parseRequestData parses the requestData of the bridge. +func parseBridgeRequestData(requestData string, mercuryVersion mercuryutils.FeedVersion) bridgeRequestData { type reqDataPayload struct { - To *string `json:"to"` - From *string `json:"from"` - Address *string `json:"address"` // used for view function ea only + Endpoint *string `json:"endpoint"` + To *string `json:"to"` + From *string `json:"from"` + Address *string `json:"address"` // used for view function ea only + Market *string `json:"market"` // used for market status ea only } type reqData struct { Data reqDataPayload `json:"data"` @@ -491,18 +505,25 @@ func getAssetSymbolFromRequestData(requestData string) string { rd := &reqData{} err := json.Unmarshal([]byte(requestData), rd) if err != nil { - return "" + return bridgeRequestData{} + } + + if mercuryVersion == 4 && ((rd.Data.Endpoint != nil && *rd.Data.Endpoint == "market-status") || (rd.Data.Market != nil && *rd.Data.Market != "")) { + return bridgeRequestData{ + AssetSymbol: *rd.Data.Market, + IsMarketStatus: true, + } } if rd.Data.From != nil && rd.Data.To != nil { - return *rd.Data.From + "/" + *rd.Data.To + return bridgeRequestData{AssetSymbol: *rd.Data.From + "/" + *rd.Data.To} } if rd.Data.Address != nil { - return *rd.Data.Address + return bridgeRequestData{AssetSymbol: *rd.Data.Address} } - return "" + return bridgeRequestData{} } // ShouldCollectEnhancedTelemetryMercury checks if enhanced telemetry should be collected and sent @@ -616,8 +637,8 @@ func getPricesFromResultsByOrder(lggr logger.Logger, startTask pipeline.TaskRunR benchmarkPrice = parsePriceFromTask(lggr, *benchmarkPriceTask) } - // mercury version 2 only supports benchmarkPrice - if mercuryVersion == 2 { + // mercury versions 2 and 4 only supports benchmarkPrice + if mercuryVersion == 2 || mercuryVersion == 4 { return benchmarkPrice, 0, 0 } diff --git a/core/services/ocrcommon/telemetry_test.go b/core/services/ocrcommon/telemetry_test.go index 631cc32ed07..ed64e45c2db 100644 --- a/core/services/ocrcommon/telemetry_test.go +++ b/core/services/ocrcommon/telemetry_test.go @@ -7,19 +7,18 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/shopspring/decimal" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap" "google.golang.org/protobuf/proto" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" mercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" mercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" - + mercuryv4 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v4" 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" @@ -274,7 +273,6 @@ func TestSendEATelemetry(t *testing.T) { expectedMessage, _ := proto.Marshal(&expectedTelemetry) wg.Wait() assert.Equal(t, expectedMessage, sentMessage) - //enhancedTelemService.StopOnce("EnhancedTelemetryService", func() error { return nil }) doneCh <- struct{}{} } @@ -446,6 +444,45 @@ var trrsMercuryV2 = pipeline.TaskRunResults{ }, } +var trrsMercuryV4 = pipeline.TaskRunResults{ + pipeline.TaskRunResult{ + Task: &pipeline.BridgeTask{ + Name: "link-usd-test-bridge-v2", + BaseTask: pipeline.NewBaseTask(0, "ds1", nil, nil, 0), + RequestData: `{"data":{"to":"LINK","from":"USD"}}`, + }, + Result: pipeline.Result{ + Value: bridgeResponse, + }, + }, + pipeline.TaskRunResult{ + Task: &pipeline.JSONParseTask{ + BaseTask: pipeline.NewBaseTask(1, "ds1_benchmark", nil, nil, 1), + }, + Result: pipeline.Result{ + Value: 123456.123456, + }, + }, + pipeline.TaskRunResult{ + Task: &pipeline.BridgeTask{ + Name: "market-status-bridge", + BaseTask: pipeline.NewBaseTask(2, "ds2", nil, nil, 2), + RequestData: `{"data":{"endpoint":"market-status","market":"forex"}}`, + }, + Result: pipeline.Result{ + Value: bridgeResponse, + }, + }, + pipeline.TaskRunResult{ + Task: &pipeline.JSONParseTask{ + BaseTask: pipeline.NewBaseTask(3, "market_status", nil, nil, 3), + }, + Result: pipeline.Result{ + Value: 2.0, + }, + }, +} + func TestGetPricesFromBridgeByTelemetryField(t *testing.T) { lggr, _ := logger.TestLoggerObserved(t, zap.WarnLevel) // These are intentionally out of order from the "legacy" method which expects order of `benchmark, bid, ask` @@ -605,12 +642,23 @@ func TestShouldCollectEnhancedTelemetryMercury(t *testing.T) { require.Equal(t, ShouldCollectEnhancedTelemetryMercury(j), false) } -func TestGetAssetSymbolFromRequestData(t *testing.T) { - require.Equal(t, getAssetSymbolFromRequestData(""), "") +func TestParseBridgeRequestData(t *testing.T) { + require.Equal(t, parseBridgeRequestData("", 2), bridgeRequestData{}) + reqData := `{"data":{"to":"LINK","from":"USD"}}` - require.Equal(t, getAssetSymbolFromRequestData(reqData), "USD/LINK") + require.Equal(t, parseBridgeRequestData(reqData, 2), bridgeRequestData{AssetSymbol: "USD/LINK"}) + + reqData = `{"data":{"to":"LINK","from":"USD","market":"forex"}}` + require.Equal(t, parseBridgeRequestData(reqData, 2), bridgeRequestData{AssetSymbol: "USD/LINK"}) + + reqData = `{"data":{"endpoint":"market-status","market":"forex"}}` + require.Equal(t, parseBridgeRequestData(reqData, 4), bridgeRequestData{AssetSymbol: "forex", IsMarketStatus: true}) + + reqData = `{"data":{"market":"metals"}}` + require.Equal(t, parseBridgeRequestData(reqData, 4), bridgeRequestData{AssetSymbol: "metals", IsMarketStatus: true}) + viewFunctionReqData := `{"data":{"address":"0x12345678", "signature": "function stEthPerToken() view returns (int256)"}}` - require.Equal(t, "0x12345678", getAssetSymbolFromRequestData(viewFunctionReqData)) + require.Equal(t, parseBridgeRequestData(viewFunctionReqData, 3), bridgeRequestData{AssetSymbol: "0x12345678"}) } func getViewFunctionTaskRunResults() pipeline.TaskRunResults { @@ -1005,3 +1053,81 @@ func TestCollectMercuryEnhancedTelemetryV2(t *testing.T) { require.Contains(t, logs.All()[3].Message, "cannot parse enhanced EA telemetry bid price") chDone <- struct{}{} } + +func TestCollectMercuryEnhancedTelemetryV4(t *testing.T) { + ingressClient := mocks.NewTelemetryService(t) + ingressAgent := telemetry.NewIngressAgentWrapper(ingressClient) + monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("test-network", "test-chainID", "0xa", synchronization.EnhancedEAMercury) + + sentMessageCh := make(chan []byte) + ingressClient.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { + sentMessageCh <- args[1].([]byte) + }) + + lggr, _ := logger.TestLoggerObserved(t, zap.WarnLevel) + chTelem := make(chan EnhancedTelemetryMercuryData, 100) + chDone := make(chan struct{}) + feedID := common.HexToHash("0x0004") + e := EnhancedTelemetryService[EnhancedTelemetryMercuryData]{ + chDone: chDone, + chTelem: chTelem, + job: &job.Job{ + Type: job.Type(pipeline.OffchainReporting2JobType), + OCR2OracleSpec: &job.OCR2OracleSpec{ + CaptureEATelemetry: true, + FeedID: &feedID, + }, + }, + lggr: lggr, + monitoringEndpoint: monitoringEndpoint, + } + servicetest.Run(t, &e) + + chTelem <- EnhancedTelemetryMercuryData{ + TaskRunResults: trrsMercuryV4, + FeedVersion: 4, + V4Observation: &mercuryv4.Observation{ + BenchmarkPrice: mercury.ObsResult[*big.Int]{Val: big.NewInt(111111)}, + MarketStatus: mercury.ObsResult[uint32]{Val: 2}, + MaxFinalizedTimestamp: mercury.ObsResult[int64]{Val: 321}, + LinkPrice: mercury.ObsResult[*big.Int]{Val: big.NewInt(4321)}, + NativePrice: mercury.ObsResult[*big.Int]{Val: big.NewInt(54321)}, + }, + RepTimestamp: types.ReportTimestamp{ + ConfigDigest: types.ConfigDigest{2}, + Epoch: 11, + Round: 22, + }, + } + + expectedPricingTelemetry := telem.EnhancedEAMercury{ + DataSource: "data-source-name", + DpBenchmarkPrice: 123456.123456, + BridgeTaskRunStartedTimestamp: trrsMercuryV4[0].CreatedAt.UnixMilli(), + BridgeTaskRunEndedTimestamp: trrsMercuryV4[0].FinishedAt.Time.UnixMilli(), + ProviderRequestedTimestamp: 92233720368547760, + ProviderReceivedTimestamp: -92233720368547760, + ProviderDataStreamEstablished: 1, + ProviderIndicatedTime: -123456789, + Feed: common.HexToHash("0x0004").String(), + ObservationBenchmarkPrice: 111111, + ObservationMarketStatus: 2, + ConfigDigest: "0200000000000000000000000000000000000000000000000000000000000000", + Round: 22, + Epoch: 11, + AssetSymbol: "USD/LINK", + ObservationBenchmarkPriceString: "111111", + MaxFinalizedTimestamp: 321, + LinkPrice: 4321, + NativePrice: 54321, + Version: 4, + BridgeRequestData: `{"data":{"to":"LINK","from":"USD"}}`, + } + expectedPricingMessage, _ := proto.Marshal(&expectedPricingTelemetry) + require.Equal(t, expectedPricingMessage, <-sentMessageCh) + + chDone <- struct{}{} + + // Verify that no other telemetry is sent. + require.Len(t, sentMessageCh, 0) +} 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 7be7ad8d706..09eed12ee8a 100644 --- a/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go +++ b/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go @@ -101,7 +101,7 @@ type EnhancedEAMercury struct { ProviderDataStreamEstablished int64 `protobuf:"varint,12,opt,name=provider_data_stream_established,json=providerDataStreamEstablished,proto3" json:"provider_data_stream_established,omitempty"` ProviderIndicatedTime int64 `protobuf:"varint,13,opt,name=provider_indicated_time,json=providerIndicatedTime,proto3" json:"provider_indicated_time,omitempty"` Feed string `protobuf:"bytes,14,opt,name=feed,proto3" json:"feed,omitempty"` - // v1+v2+v3 + // v1+v2+v3+v4 ObservationBenchmarkPrice int64 `protobuf:"varint,15,opt,name=observation_benchmark_price,json=observationBenchmarkPrice,proto3" json:"observation_benchmark_price,omitempty"` // This value overflows, will be reserved and removed in future versions ObservationBenchmarkPriceString string `protobuf:"bytes,22,opt,name=observation_benchmark_price_string,json=observationBenchmarkPriceString,proto3" json:"observation_benchmark_price_string,omitempty"` // v1+v3 diff --git a/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto b/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto index c96c58f9ea3..d57b7ca836a 100644 --- a/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto +++ b/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto @@ -44,7 +44,7 @@ message EnhancedEAMercury { string feed=14; - // v1+v2+v3 + // v1+v2+v3+v4 int64 observation_benchmark_price=15; // This value overflows, will be reserved and removed in future versions string observation_benchmark_price_string = 22; // v1+v3 From 4f9ed6404beb1272287955a71d7fe22490a64d28 Mon Sep 17 00:00:00 2001 From: momentmaker Date: Fri, 20 Sep 2024 11:29:40 -0500 Subject: [PATCH 17/20] add ccip goreleaser build (#14439) * CCIP configs * Better directory structure * Fixes * Fixes * Fixes * add ccip goreleaser build * remove matrix.build and fix dockerfile for copy ccip/config dir * try again with [g] * another try * update build-publish for ccip prod * comment test * revert comment * remove ccip.Dockerfile --------- Co-authored-by: Mateusz Sekara Co-authored-by: Mateusz Sekara --- .../workflows/build-publish-develop-pr.yml | 24 +- .github/workflows/build-publish.yml | 32 ++- .goreleaser.ccip.develop.yaml | 229 ++++++++++++++++++ .goreleaser.ccip.production.yaml | 229 ++++++++++++++++++ GNUmakefile | 10 + ccip/config/README.md | 10 + ccip/config/evm/Arbitrum_Mainnet.toml | 29 +++ ccip/config/evm/Arbitrum_Sepolia.toml | 27 +++ ccip/config/evm/Astar_Mainnet.toml | 9 + ccip/config/evm/Astar_Shibuya.toml | 9 + ccip/config/evm/Avalanche_ANZ_testnet.toml | 19 ++ ccip/config/evm/Avalanche_Fuji.toml | 21 ++ ccip/config/evm/Avalanche_Mainnet.toml | 19 ++ ccip/config/evm/BSC_Mainnet.toml | 28 +++ ccip/config/evm/BSC_Testnet.toml | 33 +++ ccip/config/evm/Base_Mainnet.toml | 31 +++ ccip/config/evm/Base_Sepolia.toml | 32 +++ ccip/config/evm/Blast_Mainnet.toml | 34 +++ ccip/config/evm/Blast_Sepolia.toml | 34 +++ ccip/config/evm/Celo_Mainnet.toml | 20 ++ ccip/config/evm/Celo_Testnet.toml | 20 ++ ccip/config/evm/Ethereum_Mainnet.toml | 17 ++ ccip/config/evm/Ethereum_Sepolia.toml | 17 ++ ccip/config/evm/Fantom_Mainnet.toml | 12 + ccip/config/evm/Fantom_Testnet.toml | 12 + ccip/config/evm/Gnosis_Chiado.toml | 10 + ccip/config/evm/Gnosis_Mainnet.toml | 18 ++ ccip/config/evm/Kroma_Mainnet.toml | 27 +++ ccip/config/evm/Kroma_Sepolia.toml | 27 +++ ccip/config/evm/L3X_Mainnet.toml | 18 ++ ccip/config/evm/L3X_Sepolia.toml | 18 ++ ccip/config/evm/Linea_Mainnet.toml | 17 ++ ccip/config/evm/Linea_Sepolia.toml | 13 + ccip/config/evm/Mantle_Sepolia.toml | 19 ++ ccip/config/evm/Metis_Mainnet.toml | 21 ++ ccip/config/evm/Metis_Sepolia.toml | 17 ++ ccip/config/evm/Mode_Mainnet.toml | 30 +++ ccip/config/evm/Mode_Sepolia.toml | 30 +++ ccip/config/evm/OKX_Mainnet.toml | 1 + ccip/config/evm/OKX_Testnet.toml | 1 + ccip/config/evm/Optimism_Mainnet.toml | 32 +++ ccip/config/evm/Optimism_Sepolia.toml | 31 +++ ccip/config/evm/Polygon_Amoy.toml | 28 +++ ccip/config/evm/Polygon_Mainnet.toml | 38 +++ ccip/config/evm/Polygon_Zkevm_Cardona.toml | 24 ++ ccip/config/evm/Polygon_Zkevm_Mainnet.toml | 26 ++ ccip/config/evm/Scroll_Mainnet.toml | 22 ++ ccip/config/evm/Scroll_Sepolia.toml | 22 ++ ccip/config/evm/Simulated.toml | 24 ++ ccip/config/evm/WeMix_Mainnet.toml | 16 ++ ccip/config/evm/WeMix_Testnet.toml | 19 ++ ccip/config/evm/XLayer_Mainnet.toml | 25 ++ ccip/config/evm/XLayer_Sepolia.toml | 25 ++ ccip/config/evm/zkSync_Mainnet.toml | 28 +++ ccip/config/evm/zkSync_Sepolia.toml | 28 +++ core/chainlink.goreleaser.Dockerfile | 5 + 56 files changed, 1596 insertions(+), 21 deletions(-) create mode 100644 .goreleaser.ccip.develop.yaml create mode 100644 .goreleaser.ccip.production.yaml create mode 100644 ccip/config/README.md create mode 100644 ccip/config/evm/Arbitrum_Mainnet.toml create mode 100644 ccip/config/evm/Arbitrum_Sepolia.toml create mode 100644 ccip/config/evm/Astar_Mainnet.toml create mode 100644 ccip/config/evm/Astar_Shibuya.toml create mode 100644 ccip/config/evm/Avalanche_ANZ_testnet.toml create mode 100644 ccip/config/evm/Avalanche_Fuji.toml create mode 100644 ccip/config/evm/Avalanche_Mainnet.toml create mode 100644 ccip/config/evm/BSC_Mainnet.toml create mode 100644 ccip/config/evm/BSC_Testnet.toml create mode 100644 ccip/config/evm/Base_Mainnet.toml create mode 100644 ccip/config/evm/Base_Sepolia.toml create mode 100644 ccip/config/evm/Blast_Mainnet.toml create mode 100644 ccip/config/evm/Blast_Sepolia.toml create mode 100644 ccip/config/evm/Celo_Mainnet.toml create mode 100644 ccip/config/evm/Celo_Testnet.toml create mode 100644 ccip/config/evm/Ethereum_Mainnet.toml create mode 100644 ccip/config/evm/Ethereum_Sepolia.toml create mode 100644 ccip/config/evm/Fantom_Mainnet.toml create mode 100644 ccip/config/evm/Fantom_Testnet.toml create mode 100644 ccip/config/evm/Gnosis_Chiado.toml create mode 100644 ccip/config/evm/Gnosis_Mainnet.toml create mode 100644 ccip/config/evm/Kroma_Mainnet.toml create mode 100644 ccip/config/evm/Kroma_Sepolia.toml create mode 100644 ccip/config/evm/L3X_Mainnet.toml create mode 100644 ccip/config/evm/L3X_Sepolia.toml create mode 100644 ccip/config/evm/Linea_Mainnet.toml create mode 100644 ccip/config/evm/Linea_Sepolia.toml create mode 100644 ccip/config/evm/Mantle_Sepolia.toml create mode 100644 ccip/config/evm/Metis_Mainnet.toml create mode 100644 ccip/config/evm/Metis_Sepolia.toml create mode 100644 ccip/config/evm/Mode_Mainnet.toml create mode 100644 ccip/config/evm/Mode_Sepolia.toml create mode 100644 ccip/config/evm/OKX_Mainnet.toml create mode 100644 ccip/config/evm/OKX_Testnet.toml create mode 100644 ccip/config/evm/Optimism_Mainnet.toml create mode 100644 ccip/config/evm/Optimism_Sepolia.toml create mode 100644 ccip/config/evm/Polygon_Amoy.toml create mode 100644 ccip/config/evm/Polygon_Mainnet.toml create mode 100644 ccip/config/evm/Polygon_Zkevm_Cardona.toml create mode 100644 ccip/config/evm/Polygon_Zkevm_Mainnet.toml create mode 100644 ccip/config/evm/Scroll_Mainnet.toml create mode 100644 ccip/config/evm/Scroll_Sepolia.toml create mode 100644 ccip/config/evm/Simulated.toml create mode 100644 ccip/config/evm/WeMix_Mainnet.toml create mode 100644 ccip/config/evm/WeMix_Testnet.toml create mode 100644 ccip/config/evm/XLayer_Mainnet.toml create mode 100644 ccip/config/evm/XLayer_Sepolia.toml create mode 100644 ccip/config/evm/zkSync_Mainnet.toml create mode 100644 ccip/config/evm/zkSync_Sepolia.toml diff --git a/.github/workflows/build-publish-develop-pr.yml b/.github/workflows/build-publish-develop-pr.yml index 3a05078d3ea..2868616ace0 100644 --- a/.github/workflows/build-publish-develop-pr.yml +++ b/.github/workflows/build-publish-develop-pr.yml @@ -21,6 +21,15 @@ env: jobs: goreleaser-build-publish-chainlink: + name: "goreleaser-build-publish-${{ matrix.image-name }}" + strategy: + fail-fast: false + matrix: + include: + - image-name: chainlink + goreleaser-config: .goreleaser.develop.yaml + - image-name: ccip + goreleaser-config: .goreleaser.ccip.develop.yaml runs-on: ubuntu-20.04 permissions: id-token: write @@ -68,18 +77,18 @@ jobs: 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 + role-session-name: goreleaser-build-publish-${{ matrix.image-name }} - 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-name: ${{ matrix.image-name }} 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-config: ${{ matrix.goreleaser-config }} goreleaser-key: ${{ secrets.GORELEASER_KEY }} zig-version: 0.11.0 @@ -87,13 +96,6 @@ jobs: 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") | "\(.name)"' ${artifact_path} >> output.txt while read -r line; do @@ -109,5 +111,5 @@ jobs: 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 + this-job-name: goreleaser-build-publish-${{ matrix.image-name }} continue-on-error: true \ No newline at end of file diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index ba274730bfc..ca6a2d5275a 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -98,15 +98,27 @@ jobs: mask-aws-account-id: true role-session-name: goreleaser-build-sign-publish-chainlink + - name: Set build configs + shell: bash + id: set-build-configs + run: | + if [[ ${{ github.ref_name }} =~ "-ccip" ]]; then + echo "ECR_IMAGE_NAME=chainlink/ccip" | tee -a $GITHUB_OUTPUT + echo "GORELEASER_CONFIG=.goreleaser.ccip.production.yaml" | tee -a $GITHUB_OUTPUT + else + echo "ECR_IMAGE_NAME=chainlink/chainlink" | tee -a $GITHUB_OUTPUT + echo "GORELEASER_CONFIG=.goreleaser.production.yaml" | tee -a $GITHUB_OUTPUT + fi + - name: Build, sign, and publish image id: goreleaser-build-sign-publish uses: ./.github/actions/goreleaser-build-sign-publish with: docker-registry: ${{ env.ECR_HOSTNAME}} - docker-image-name: ${{ env.ECR_IMAGE_NAME }} + docker-image-name: ${{ steps.set-build-configs.outputs.ECR_IMAGE_NAME }} docker-image-tag: ${{ github.ref_name }} goreleaser-exec: ./tools/bin/goreleaser_wrapper - goreleaser-config: .goreleaser.production.yaml + goreleaser-config: ${{ steps.set-build-configs.outputs.GORELEASER_CONFIG }} goreleaser-key: ${{ secrets.GORELEASER_KEY }} zig-version: 0.11.0 enable-cosign: true @@ -124,10 +136,10 @@ jobs: echo "$line" | tee -a "$GITHUB_STEP_SUMMARY" done < output.txt - core_amd64_name="${{ env.ECR_HOSTNAME }}/${{ env.ECR_IMAGE_NAME }}:${{ github.ref_name }}-amd64" - plugins_amd64_name="${{ env.ECR_HOSTNAME }}/${{ env.ECR_IMAGE_NAME }}:${{ github.ref_name }}-plugins-amd64" - core_arm64_name="${{ env.ECR_HOSTNAME }}/${{ env.ECR_IMAGE_NAME }}:${{ github.ref_name }}-arm64" - plugins_arm64_name="${{ env.ECR_HOSTNAME }}/${{ env.ECR_IMAGE_NAME }}:${{ github.ref_name }}-plugins-arm64" + core_amd64_name="${{ env.ECR_HOSTNAME }}/${{ steps.set-build-configs.outputs.ECR_IMAGE_NAME }}:${{ github.ref_name }}-amd64" + plugins_amd64_name="${{ env.ECR_HOSTNAME }}/${{ steps.set-build-configs.outputs.ECR_IMAGE_NAME }}:${{ github.ref_name }}-plugins-amd64" + core_arm64_name="${{ env.ECR_HOSTNAME }}/${{ steps.set-build-configs.outputs.ECR_IMAGE_NAME }}:${{ github.ref_name }}-arm64" + plugins_arm64_name="${{ env.ECR_HOSTNAME }}/${{ steps.set-build-configs.outputs.ECR_IMAGE_NAME }}:${{ github.ref_name }}-plugins-arm64" echo "core_amd64_digest=$(jq -r --arg name "$core_amd64_name" '.[]|select(.type=="Published Docker Image" and .name==$name)|.extra.Digest' ${artifact_path})" | tee -a "$GITHUB_OUTPUT" "$GITHUB_STEP_SUMMARY" echo "plugins_amd64_digest=$(jq -r --arg name "$plugins_amd64_name" '.[]|select(.type=="Published Docker Image" and .name==$name)|.extra.Digest' ${artifact_path})" | tee -a "$GITHUB_OUTPUT" "$GITHUB_STEP_SUMMARY" @@ -143,28 +155,28 @@ jobs: uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2 with: subject-digest: ${{ steps.get-image-name-digest.outputs.core_amd64_digest }} - subject-name: ${{ env.ECR_HOSTNAME }}/${{ env.ECR_IMAGE_NAME }} + subject-name: ${{ env.ECR_HOSTNAME }}/${{ steps.set-build-configs.outputs.ECR_IMAGE_NAME }} push-to-registry: true - name: Attest Docker image (plugins-amd64) uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2 with: subject-digest: ${{ steps.get-image-name-digest.outputs.plugins_amd64_digest }} - subject-name: ${{ env.ECR_HOSTNAME }}/${{ env.ECR_IMAGE_NAME }} + subject-name: ${{ env.ECR_HOSTNAME }}/${{ steps.set-build-configs.outputs.ECR_IMAGE_NAME }} push-to-registry: true - name: Attest Docker image (core-arm64) uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2 with: subject-digest: ${{ steps.get-image-name-digest.outputs.core_arm64_digest }} - subject-name: ${{ env.ECR_HOSTNAME }}/${{ env.ECR_IMAGE_NAME }} + subject-name: ${{ env.ECR_HOSTNAME }}/${{ steps.set-build-configs.outputs.ECR_IMAGE_NAME }} push-to-registry: true - name: Attest Docker image (plugins-arm64) uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2 with: subject-digest: ${{ steps.get-image-name-digest.outputs.plugins_arm64_digest }} - subject-name: ${{ env.ECR_HOSTNAME }}/${{ env.ECR_IMAGE_NAME }} + subject-name: ${{ env.ECR_HOSTNAME }}/${{ steps.set-build-configs.outputs.ECR_IMAGE_NAME }} push-to-registry: true - name: Upload SBOMs diff --git a/.goreleaser.ccip.develop.yaml b/.goreleaser.ccip.develop.yaml new file mode 100644 index 00000000000..595fe14c27b --- /dev/null +++ b/.goreleaser.ccip.develop.yaml @@ -0,0 +1,229 @@ +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 }}" + +before: + hooks: + - go mod tidy + - ./tools/bin/goreleaser_utils before_hook + +# See https://goreleaser.com/customization/build/ +builds: + - binary: chainlink + id: linux-arm64 + goos: + - linux + goarch: + - arm64 + hooks: + post: ./tools/bin/goreleaser_utils build_post_hook {{ dir .Path }} {{ .Os }} {{ .Arch }} + env: + - CGO_ENABLED=1 + - CC=$ZIG_EXEC cc -target aarch64-linux-gnu + - CCX=$ZIG_EXEC c++ -target aarch64-linux-gnu + flags: + - -trimpath + - -buildmode=pie + ldflags: + - -s -w -r=$ORIGIN/libs + - -X github.com/smartcontractkit/chainlink/v2/core/static.Version={{ .Env.CHAINLINK_VERSION }} + - -X github.com/smartcontractkit/chainlink/v2/core/static.Sha={{ .FullCommit }} + - binary: chainlink + id: linux-amd64 + goos: + - linux + goarch: + - amd64 + hooks: + post: ./tools/bin/goreleaser_utils build_post_hook {{ dir .Path }} {{ .Os }} {{ .Arch }} + env: + - CGO_ENABLED=1 + - CC=$ZIG_EXEC cc -target x86_64-linux-gnu + - CCX=$ZIG_EXEC c++ -target x86_64-linux-gnu + flags: + - -trimpath + - -buildmode=pie + ldflags: + - -s -w -r=$ORIGIN/libs + - -X github.com/smartcontractkit/chainlink/v2/core/static.Version={{ .Env.CHAINLINK_VERSION }} + - -X github.com/smartcontractkit/chainlink/v2/core/static.Sha={{ .FullCommit }} + +# See https://goreleaser.com/customization/docker/ +dockers: + - id: linux-amd64 + dockerfile: core/chainlink.goreleaser.Dockerfile + use: buildx + goos: linux + goarch: amd64 + extra_files: + - tmp/linux_amd64/libs + - tools/bin/ldd_fix + - ccip/config + build_flag_templates: + - "--platform=linux/amd64" + - "--pull" + - "--build-arg=CHAINLINK_USER=chainlink" + - "--build-arg=COMMIT_SHA={{ .FullCommit }}" + - "--build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config" + - "--label=org.opencontainers.image.created={{ .Date }}" + - "--label=org.opencontainers.image.description={{ .Env.IMAGE_LABEL_DESCRIPTION }}" + - "--label=org.opencontainers.image.licenses={{ .Env.IMAGE_LABEL_LICENSES }}" + - "--label=org.opencontainers.image.revision={{ .FullCommit }}" + - "--label=org.opencontainers.image.source={{ .Env.IMAGE_LABEL_SOURCE }}" + - "--label=org.opencontainers.image.title={{ .ProjectName }}" + - "--label=org.opencontainers.image.version={{ .Env.CHAINLINK_VERSION }}" + - "--label=org.opencontainers.image.url={{ .Env.IMAGE_LABEL_SOURCE }}" + image_templates: + - "{{ .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 + - tools/bin/ldd_fix + - ccip/config + build_flag_templates: + - "--platform=linux/arm64" + - "--pull" + - "--build-arg=CHAINLINK_USER=chainlink" + - "--build-arg=COMMIT_SHA={{ .FullCommit }}" + - "--build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config" + - "--label=org.opencontainers.image.created={{ .Date }}" + - "--label=org.opencontainers.image.description={{ .Env.IMAGE_LABEL_DESCRIPTION }}" + - "--label=org.opencontainers.image.licenses={{ .Env.IMAGE_LABEL_LICENSES }}" + - "--label=org.opencontainers.image.revision={{ .FullCommit }}" + - "--label=org.opencontainers.image.source={{ .Env.IMAGE_LABEL_SOURCE }}" + - "--label=org.opencontainers.image.title={{ .ProjectName }}" + - "--label=org.opencontainers.image.version={{ .Env.CHAINLINK_VERSION }}" + - "--label=org.opencontainers.image.url={{ .Env.IMAGE_LABEL_SOURCE }}" + image_templates: + - "{{ .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 + goarch: amd64 + extra_files: + - tmp/linux_amd64/libs + - tmp/linux_amd64/plugins + - tools/bin/ldd_fix + - ccip/config + build_flag_templates: + - "--platform=linux/amd64" + - "--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" + - "--build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config" + - "--label=org.opencontainers.image.created={{ .Date }}" + - "--label=org.opencontainers.image.description={{ .Env.IMAGE_LABEL_DESCRIPTION }}" + - "--label=org.opencontainers.image.licenses={{ .Env.IMAGE_LABEL_LICENSES }}" + - "--label=org.opencontainers.image.revision={{ .FullCommit }}" + - "--label=org.opencontainers.image.source={{ .Env.IMAGE_LABEL_SOURCE }}" + - "--label=org.opencontainers.image.title={{ .ProjectName }}" + - "--label=org.opencontainers.image.version={{ .Env.CHAINLINK_VERSION }}" + - "--label=org.opencontainers.image.url={{ .Env.IMAGE_LABEL_SOURCE }}" + image_templates: + - "{{ .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 + goarch: arm64 + extra_files: + - tmp/linux_arm64/libs + - tmp/linux_arm64/plugins + - tools/bin/ldd_fix + - ccip/config + build_flag_templates: + - "--platform=linux/arm64" + - "--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" + - "--build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config" + - "--label=org.opencontainers.image.created={{ .Date }}" + - "--label=org.opencontainers.image.description={{ .Env.IMAGE_LABEL_DESCRIPTION }}" + - "--label=org.opencontainers.image.licenses={{ .Env.IMAGE_LABEL_LICENSES }}" + - "--label=org.opencontainers.image.revision={{ .FullCommit }}" + - "--label=org.opencontainers.image.source={{ .Env.IMAGE_LABEL_SOURCE }}" + - "--label=org.opencontainers.image.title={{ .ProjectName }}" + - "--label=org.opencontainers.image.version={{ .Env.CHAINLINK_VERSION }}" + - "--label=org.opencontainers.image.url={{ .Env.IMAGE_LABEL_SOURCE }}" + image_templates: + - "{{ .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 }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}" + image_templates: + - "{{ .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 }}/{{ .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 }}/{{ .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 }}/{{ .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: + - artifacts: all + args: + - "sign" + - "${artifact}" + - "--yes" + +checksum: + name_template: "checksums.txt" + +snapshot: + version_template: "{{ .Env.CHAINLINK_VERSION }}-{{ .ShortCommit }}" + +partial: + by: target + +# See https://goreleaser.com/customization/release/ +release: + disable: true + +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" +# modelines, feel free to remove those if you don't want/use them: +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json +# vim: set ts=2 sw=2 tw=0 fo=cnqoj diff --git a/.goreleaser.ccip.production.yaml b/.goreleaser.ccip.production.yaml new file mode 100644 index 00000000000..1247be143ca --- /dev/null +++ b/.goreleaser.ccip.production.yaml @@ -0,0 +1,229 @@ +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 }}" + +before: + hooks: + - go mod tidy + - ./tools/bin/goreleaser_utils before_hook + +# See https://goreleaser.com/customization/build/ +builds: + - binary: chainlink + id: linux-arm64 + goos: + - linux + goarch: + - arm64 + hooks: + post: ./tools/bin/goreleaser_utils build_post_hook {{ dir .Path }} {{ .Os }} {{ .Arch }} + env: + - CGO_ENABLED=1 + - CC=$ZIG_EXEC cc -target aarch64-linux-gnu + - CCX=$ZIG_EXEC c++ -target aarch64-linux-gnu + flags: + - -trimpath + - -buildmode=pie + ldflags: + - -s -w -r=$ORIGIN/libs + - -X github.com/smartcontractkit/chainlink/v2/core/static.Version={{ .Env.CHAINLINK_VERSION }} + - -X github.com/smartcontractkit/chainlink/v2/core/static.Sha={{ .FullCommit }} + - binary: chainlink + id: linux-amd64 + goos: + - linux + goarch: + - amd64 + hooks: + post: ./tools/bin/goreleaser_utils build_post_hook {{ dir .Path }} {{ .Os }} {{ .Arch }} + env: + - CGO_ENABLED=1 + - CC=$ZIG_EXEC cc -target x86_64-linux-gnu + - CCX=$ZIG_EXEC c++ -target x86_64-linux-gnu + flags: + - -trimpath + - -buildmode=pie + ldflags: + - -s -w -r=$ORIGIN/libs + - -X github.com/smartcontractkit/chainlink/v2/core/static.Version={{ .Env.CHAINLINK_VERSION }} + - -X github.com/smartcontractkit/chainlink/v2/core/static.Sha={{ .FullCommit }} + +# See https://goreleaser.com/customization/docker/ +dockers: + - id: linux-amd64 + dockerfile: core/chainlink.goreleaser.Dockerfile + use: buildx + goos: linux + goarch: amd64 + extra_files: + - tmp/linux_amd64/libs + - tools/bin/ldd_fix + - ccip/config + build_flag_templates: + - "--platform=linux/amd64" + - "--pull" + - "--build-arg=CHAINLINK_USER=chainlink" + - "--build-arg=COMMIT_SHA={{ .FullCommit }}" + - "--build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config" + - "--label=org.opencontainers.image.created={{ .Date }}" + - "--label=org.opencontainers.image.description={{ .Env.IMAGE_LABEL_DESCRIPTION }}" + - "--label=org.opencontainers.image.licenses={{ .Env.IMAGE_LABEL_LICENSES }}" + - "--label=org.opencontainers.image.revision={{ .FullCommit }}" + - "--label=org.opencontainers.image.source={{ .Env.IMAGE_LABEL_SOURCE }}" + - "--label=org.opencontainers.image.title={{ .ProjectName }}" + - "--label=org.opencontainers.image.version={{ .Env.CHAINLINK_VERSION }}" + - "--label=org.opencontainers.image.url={{ .Env.IMAGE_LABEL_SOURCE }}" + image_templates: + - "{{ .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 + - tools/bin/ldd_fix + - ccip/config + build_flag_templates: + - "--platform=linux/arm64" + - "--pull" + - "--build-arg=CHAINLINK_USER=chainlink" + - "--build-arg=COMMIT_SHA={{ .FullCommit }}" + - "--build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config" + - "--label=org.opencontainers.image.created={{ .Date }}" + - "--label=org.opencontainers.image.description={{ .Env.IMAGE_LABEL_DESCRIPTION }}" + - "--label=org.opencontainers.image.licenses={{ .Env.IMAGE_LABEL_LICENSES }}" + - "--label=org.opencontainers.image.revision={{ .FullCommit }}" + - "--label=org.opencontainers.image.source={{ .Env.IMAGE_LABEL_SOURCE }}" + - "--label=org.opencontainers.image.title={{ .ProjectName }}" + - "--label=org.opencontainers.image.version={{ .Env.CHAINLINK_VERSION }}" + - "--label=org.opencontainers.image.url={{ .Env.IMAGE_LABEL_SOURCE }}" + image_templates: + - "{{ .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 + goarch: amd64 + extra_files: + - tmp/linux_amd64/libs + - tmp/linux_amd64/plugins + - tools/bin/ldd_fix + - ccip/config + build_flag_templates: + - "--platform=linux/amd64" + - "--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" + - "--build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config" + - "--label=org.opencontainers.image.created={{ .Date }}" + - "--label=org.opencontainers.image.description={{ .Env.IMAGE_LABEL_DESCRIPTION }}" + - "--label=org.opencontainers.image.licenses={{ .Env.IMAGE_LABEL_LICENSES }}" + - "--label=org.opencontainers.image.revision={{ .FullCommit }}" + - "--label=org.opencontainers.image.source={{ .Env.IMAGE_LABEL_SOURCE }}" + - "--label=org.opencontainers.image.title={{ .ProjectName }}" + - "--label=org.opencontainers.image.version={{ .Env.CHAINLINK_VERSION }}" + - "--label=org.opencontainers.image.url={{ .Env.IMAGE_LABEL_SOURCE }}" + image_templates: + - "{{ .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 + goarch: arm64 + extra_files: + - tmp/linux_arm64/libs + - tmp/linux_arm64/plugins + - tools/bin/ldd_fix + - ccip/config + build_flag_templates: + - "--platform=linux/arm64" + - "--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" + - "--build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config" + - "--label=org.opencontainers.image.created={{ .Date }}" + - "--label=org.opencontainers.image.description={{ .Env.IMAGE_LABEL_DESCRIPTION }}" + - "--label=org.opencontainers.image.licenses={{ .Env.IMAGE_LABEL_LICENSES }}" + - "--label=org.opencontainers.image.revision={{ .FullCommit }}" + - "--label=org.opencontainers.image.source={{ .Env.IMAGE_LABEL_SOURCE }}" + - "--label=org.opencontainers.image.title={{ .ProjectName }}" + - "--label=org.opencontainers.image.version={{ .Env.CHAINLINK_VERSION }}" + - "--label=org.opencontainers.image.url={{ .Env.IMAGE_LABEL_SOURCE }}" + image_templates: + - "{{ .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 }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}" + image_templates: + - "{{ .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 }}/{{ .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 }}/{{ .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 }}/{{ .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: + - artifacts: all + args: + - "sign" + - "${artifact}" + - "--yes" + +checksum: + name_template: "checksums.txt" + +# See https://goreleaser.com/customization/sbom +sboms: + - artifacts: archive + +snapshot: + version_template: "{{ .Env.CHAINLINK_VERSION }}-{{ .ShortCommit }}" + +partial: + by: target + +# See https://goreleaser.com/customization/release/ +release: + disable: true + +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" +# modelines, feel free to remove those if you don't want/use them: +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json +# vim: set ts=2 sw=2 tw=0 fo=cnqoj diff --git a/GNUmakefile b/GNUmakefile index 23082a1f5ae..e2a3508e199 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -70,6 +70,16 @@ docker: --build-arg COMMIT_SHA=$(COMMIT_SHA) \ -f core/chainlink.Dockerfile . +.PHONY: docker-ccip ## Build the chainlink docker image +docker-ccip: + docker buildx build \ + --build-arg COMMIT_SHA=$(COMMIT_SHA) \ + -f core/chainlink.Dockerfile . -t chainlink-ccip:latest + + docker buildx build \ + --build-arg COMMIT_SHA=$(COMMIT_SHA) \ + -f ccip/ccip.Dockerfile . + .PHONY: docker-plugins ## Build the chainlink-plugins docker image docker-plugins: docker buildx build \ diff --git a/ccip/config/README.md b/ccip/config/README.md new file mode 100644 index 00000000000..f5cd87e688e --- /dev/null +++ b/ccip/config/README.md @@ -0,0 +1,10 @@ +# Default Configurations + +:warning: IMPORTANT :warning: + +This directory contains configs that are specific to the CCIP build. Apply changes here only if related to the CCIP. + + +All config sets **inherit** from `fallback.toml` first and overwrite +fields as necessary. Do not create a new full configuration from +scratch. diff --git a/ccip/config/evm/Arbitrum_Mainnet.toml b/ccip/config/evm/Arbitrum_Mainnet.toml new file mode 100644 index 00000000000..e3dcafd56fb --- /dev/null +++ b/ccip/config/evm/Arbitrum_Mainnet.toml @@ -0,0 +1,29 @@ +# Arbitrum is an L2 chain. Pending proper L2 support, for now we rely on their sequencer +ChainID = '42161' +ChainType = 'arbitrum' +FinalityTagEnabled = true +LinkContractAddress = "0xf97f4df75117a78c1A5a0DBb814Af92458539FB4" +LogPollInterval = '1s' +# Arbitrum only emits blocks when a new tx is received, so this method of liveness detection is not useful +NoNewHeadsThreshold = '0' +OCR.ContractConfirmations = 1 + +[GasEstimator] +Mode = 'Arbitrum' +LimitMax = 1_000_000_000 +# Arbitrum uses the suggested gas price, so we don't want to place any limits on the minimum +PriceMin = '0' +PriceDefault = '0.1 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +FeeCapDefault = '1000 gwei' +BumpThreshold = 5 + +[GasEstimator.BlockHistory] +# Force an error if someone set GAS_UPDATER_ENABLED=true by accident; we never want to run the block history estimator on arbitrum +BlockHistorySize = 0 + +[NodePool] +SyncThreshold = 10 + +[OCR2.Automation] +GasLimit = 14500000 diff --git a/ccip/config/evm/Arbitrum_Sepolia.toml b/ccip/config/evm/Arbitrum_Sepolia.toml new file mode 100644 index 00000000000..ea994cf7c78 --- /dev/null +++ b/ccip/config/evm/Arbitrum_Sepolia.toml @@ -0,0 +1,27 @@ +ChainID = '421614' +ChainType = 'arbitrum' +FinalityTagEnabled = true +LinkContractAddress = '0xE4aB69C077896252FAFBD49EFD26B5D171A32410' +NoNewHeadsThreshold = '0' +OCR.ContractConfirmations = 1 +LogPollInterval = '1s' + +[GasEstimator] +Mode = 'Arbitrum' +LimitMax = 1_000_000_000 +# Arbitrum uses the suggested gas price, so we don't want to place any limits on the minimum +PriceMin = '0' +PriceDefault = '0.1 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +FeeCapDefault = '1000 gwei' +BumpThreshold = 5 + +[GasEstimator.BlockHistory] +# Force an error if someone set GAS_UPDATER_ENABLED=true by accident; we never want to run the block history estimator on arbitrum +BlockHistorySize = 0 + +[NodePool] +SyncThreshold = 10 + +[OCR2.Automation] +GasLimit = 14500000 diff --git a/ccip/config/evm/Astar_Mainnet.toml b/ccip/config/evm/Astar_Mainnet.toml new file mode 100644 index 00000000000..87808001eb7 --- /dev/null +++ b/ccip/config/evm/Astar_Mainnet.toml @@ -0,0 +1,9 @@ +ChainID = '592' +FinalityTagEnabled = true +FinalityDepth = 100 +LogPollInterval = '6s' + +[GasEstimator] +EIP1559DynamicFees = false +PriceMax = '100000 gwei' +LimitDefault = 8000000 \ No newline at end of file diff --git a/ccip/config/evm/Astar_Shibuya.toml b/ccip/config/evm/Astar_Shibuya.toml new file mode 100644 index 00000000000..5a5df06f6f0 --- /dev/null +++ b/ccip/config/evm/Astar_Shibuya.toml @@ -0,0 +1,9 @@ +ChainID = '81' +FinalityTagEnabled = true +FinalityDepth = 100 +LogPollInterval = '6s' + +[GasEstimator] +EIP1559DynamicFees = false +PriceMax = '100000 gwei' +LimitDefault = 8000000 \ No newline at end of file diff --git a/ccip/config/evm/Avalanche_ANZ_testnet.toml b/ccip/config/evm/Avalanche_ANZ_testnet.toml new file mode 100644 index 00000000000..4833881bf48 --- /dev/null +++ b/ccip/config/evm/Avalanche_ANZ_testnet.toml @@ -0,0 +1,19 @@ +ChainID = '76578' +FinalityDepth = 1 +FinalityTagEnabled = false +LinkContractAddress = '0x779877A7B0D9E8603169DdbD7836e478b4624789' +LogPollInterval = '3s' +MinIncomingConfirmations = 1 +# Avax subnet only emits blocks when a new tx is received, so this method of liveness detection is not useful. +NoNewHeadsThreshold = '0' +OCR.ContractConfirmations = 1 +RPCBlockQueryDelay = 2 + +[GasEstimator] +Mode = 'BlockHistory' +PriceDefault = '25 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '25 gwei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 diff --git a/ccip/config/evm/Avalanche_Fuji.toml b/ccip/config/evm/Avalanche_Fuji.toml new file mode 100644 index 00000000000..5ba2e3cdc70 --- /dev/null +++ b/ccip/config/evm/Avalanche_Fuji.toml @@ -0,0 +1,21 @@ +ChainID = '43113' +FinalityDepth = 1 +FinalityTagEnabled = true +LinkContractAddress = '0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846' +LogPollInterval = '3s' +MinIncomingConfirmations = 1 +NoNewHeadsThreshold = '30s' +OCR.ContractConfirmations = 1 +RPCBlockQueryDelay = 2 +NoNewFinalizedHeadsThreshold = '1m' + +[GasEstimator] +PriceDefault = '25 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '25 gwei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[HeadTracker] +FinalityTagBypass = false diff --git a/ccip/config/evm/Avalanche_Mainnet.toml b/ccip/config/evm/Avalanche_Mainnet.toml new file mode 100644 index 00000000000..e7813842b4b --- /dev/null +++ b/ccip/config/evm/Avalanche_Mainnet.toml @@ -0,0 +1,19 @@ +ChainID = '43114' +FinalityDepth = 1 +FinalityTagEnabled = true +LinkContractAddress = '0x5947BB275c521040051D82396192181b413227A3' +LogPollInterval = '3s' +MinIncomingConfirmations = 1 +NoNewHeadsThreshold = '30s' +OCR.ContractConfirmations = 1 +RPCBlockQueryDelay = 2 +NoNewFinalizedHeadsThreshold = '1m' + +[GasEstimator] +PriceDefault = '25 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '25 gwei' + +[GasEstimator.BlockHistory] +# Average block time of 2s +BlockHistorySize = 24 diff --git a/ccip/config/evm/BSC_Mainnet.toml b/ccip/config/evm/BSC_Mainnet.toml new file mode 100644 index 00000000000..10f4c570bef --- /dev/null +++ b/ccip/config/evm/BSC_Mainnet.toml @@ -0,0 +1,28 @@ +# BSC uses Clique consensus with ~3s block times +# Clique offers finality within (N/2)+1 blocks where N is number of signers +# There are 21 BSC validators so theoretically finality should occur after 21/2+1 = 11 blocks +ChainID = '56' +# Keeping this >> 11 because it's not expensive and gives us a safety margin +FinalityDepth = 50 +FinalityTagEnabled = true +LinkContractAddress = '0x404460C6A5EdE2D891e8297795264fDe62ADBB75' +LogPollInterval = '3s' +NoNewHeadsThreshold = '30s' +RPCBlockQueryDelay = 2 +NoNewFinalizedHeadsThreshold = '45s' + +[GasEstimator] +PriceDefault = '5 gwei' +# 15s delay since feeds update every minute in volatile situations +BumpThreshold = 5 + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[OCR] +DatabaseTimeout = '2s' +ContractTransmitterTransmitTimeout = '2s' +ObservationGracePeriod = '500ms' + +[NodePool] +SyncThreshold = 10 diff --git a/ccip/config/evm/BSC_Testnet.toml b/ccip/config/evm/BSC_Testnet.toml new file mode 100644 index 00000000000..b27a877812b --- /dev/null +++ b/ccip/config/evm/BSC_Testnet.toml @@ -0,0 +1,33 @@ +# BSC uses Clique consensus with ~3s block times +# Clique offers finality within (N/2)+1 blocks where N is number of signers +# There are 21 BSC validators so theoretically finality should occur after 21/2+1 = 11 blocks +ChainID = '97' +# Keeping this >> 11 because it's not expensive and gives us a safety margin +FinalityDepth = 50 +FinalityTagEnabled = true +LinkContractAddress = '0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06' +LogPollInterval = '3s' +NoNewHeadsThreshold = '30s' +RPCBlockQueryDelay = 2 +NoNewFinalizedHeadsThreshold = '40s' + +[GasEstimator] +PriceDefault = '5 gwei' +# 15s delay since feeds update every minute in volatile situations +BumpThreshold = 5 + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[HeadTracker] +HistoryDepth = 100 +SamplingInterval = '1s' +FinalityTagBypass = false + +[OCR] +DatabaseTimeout = '2s' +ContractTransmitterTransmitTimeout = '2s' +ObservationGracePeriod = '500ms' + +[NodePool] +SyncThreshold = 10 diff --git a/ccip/config/evm/Base_Mainnet.toml b/ccip/config/evm/Base_Mainnet.toml new file mode 100644 index 00000000000..da38182b194 --- /dev/null +++ b/ccip/config/evm/Base_Mainnet.toml @@ -0,0 +1,31 @@ +ChainID = '8453' +ChainType = 'optimismBedrock' +FinalityDepth = 200 +FinalityTagEnabled = true +LogPollInterval = '2s' +NoNewHeadsThreshold = '40s' +MinIncomingConfirmations = 1 +NoNewFinalizedHeadsThreshold = '15m' + +[GasEstimator] +EIP1559DynamicFees = true +PriceMin = '1 wei' +BumpMin = '100 wei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[Transactions] +ResendAfterThreshold = '30s' + +[HeadTracker] +HistoryDepth = 300 + +[NodePool] +SyncThreshold = 10 + +[OCR] +ContractConfirmations = 1 + +[OCR2.Automation] +GasLimit = 6500000 diff --git a/ccip/config/evm/Base_Sepolia.toml b/ccip/config/evm/Base_Sepolia.toml new file mode 100644 index 00000000000..92f7717b27d --- /dev/null +++ b/ccip/config/evm/Base_Sepolia.toml @@ -0,0 +1,32 @@ +ChainID = '84532' +ChainType = 'optimismBedrock' +FinalityDepth = 200 +FinalityTagEnabled = true +LinkContractAddress = '0xE4aB69C077896252FAFBD49EFD26B5D171A32410' +LogPollInterval = '2s' +NoNewHeadsThreshold = '40s' +MinIncomingConfirmations = 1 +NoNewFinalizedHeadsThreshold = '12m' + +[GasEstimator] +EIP1559DynamicFees = true +PriceMin = '1 wei' +BumpMin = '100 wei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 60 + +[Transactions] +ResendAfterThreshold = '30s' + +[HeadTracker] +HistoryDepth = 300 + +[NodePool] +SyncThreshold = 10 + +[OCR] +ContractConfirmations = 1 + +[OCR2.Automation] +GasLimit = 6500000 diff --git a/ccip/config/evm/Blast_Mainnet.toml b/ccip/config/evm/Blast_Mainnet.toml new file mode 100644 index 00000000000..f8b501723ff --- /dev/null +++ b/ccip/config/evm/Blast_Mainnet.toml @@ -0,0 +1,34 @@ +ChainID = '81457' +FinalityDepth = 200 +FinalityTagEnabled = true +ChainType = 'optimismBedrock' +# block rate is ~2sec, so this ensures blocks are polled correctly +LogPollInterval = '2s' + +[GasEstimator] +EIP1559DynamicFees = true +BumpThreshold = 60 +BumpPercent = 20 +BumpMin = '100 wei' +PriceMax = '120 gwei' +LimitDefault = 8000000 +FeeCapDefault = '120 gwei' + +[GasEstimator.BlockHistory] +# Default is 24, which leads to bumpy gas prices. In CCIP +# we want to smooth out the gas prices, so we increase the sample size. +BlockHistorySize = 200 +# The formula for FeeCap is (current block base fee * (1.125 ^ EIP1559FeeCapBufferBlocks) + tipcap) +# where tipcap is managed by the block history estimators. In the context of CCIP, +# the gas price is relayed to other changes for quotes so we want accurate/avg not pessimistic values. +# So we set this to zero so FeeCap = baseFee + tipcap. +EIP1559FeeCapBufferBlocks = 0 + +[HeadTracker] +HistoryDepth = 300 + +[NodePool] +# 4 block sync time between nodes to ensure they aren't labelled unreachable too soon +PollFailureThreshold = 4 +# polls every 4sec to check if there is a block produced, since blockRate is ~3sec +PollInterval = '4s' \ No newline at end of file diff --git a/ccip/config/evm/Blast_Sepolia.toml b/ccip/config/evm/Blast_Sepolia.toml new file mode 100644 index 00000000000..96dc5c67871 --- /dev/null +++ b/ccip/config/evm/Blast_Sepolia.toml @@ -0,0 +1,34 @@ +ChainID = '168587773' +FinalityDepth = 200 +FinalityTagEnabled = true +ChainType = 'optimismBedrock' +# block rate is ~2sec, so this ensures blocks are polled correctly +LogPollInterval = '2s' + +[GasEstimator] +EIP1559DynamicFees = true +BumpThreshold = 60 +BumpPercent = 20 +BumpMin = '100 wei' +PriceMax = '120 gwei' +LimitDefault = 8000000 +FeeCapDefault = '120 gwei' + +[GasEstimator.BlockHistory] +# Default is 24, which leads to bumpy gas prices. In CCIP +# we want to smooth out the gas prices, so we increase the sample size. +BlockHistorySize = 200 +# The formula for FeeCap is (current block base fee * (1.125 ^ EIP1559FeeCapBufferBlocks) + tipcap) +# where tipcap is managed by the block history estimators. In the context of CCIP, +# the gas price is relayed to other changes for quotes so we want accurate/avg not pessimistic values. +# So we set this to zero so FeeCap = baseFee + tipcap. +EIP1559FeeCapBufferBlocks = 0 + +[HeadTracker] +HistoryDepth = 300 + +[NodePool] +# 4 block sync time between nodes to ensure they aren't labelled unreachable too soon +PollFailureThreshold = 4 +# polls every 4sec to check if there is a block produced, since blockRate is ~3sec +PollInterval = '4s' \ No newline at end of file diff --git a/ccip/config/evm/Celo_Mainnet.toml b/ccip/config/evm/Celo_Mainnet.toml new file mode 100644 index 00000000000..a4948620370 --- /dev/null +++ b/ccip/config/evm/Celo_Mainnet.toml @@ -0,0 +1,20 @@ +ChainID = '42220' +ChainType = 'celo' +FinalityDepth = 10 +LogPollInterval = '5s' +MinIncomingConfirmations = 1 +NoNewHeadsThreshold = '1m' +OCR.ContractConfirmations = 1 +NoNewFinalizedHeadsThreshold = '1m' + +[GasEstimator] +PriceDefault = '5 gwei' +PriceMax = '500 gwei' +PriceMin = '5 gwei' +BumpMin = '2 gwei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 12 + +[HeadTracker] +HistoryDepth = 50 diff --git a/ccip/config/evm/Celo_Testnet.toml b/ccip/config/evm/Celo_Testnet.toml new file mode 100644 index 00000000000..eb43f080b7d --- /dev/null +++ b/ccip/config/evm/Celo_Testnet.toml @@ -0,0 +1,20 @@ +ChainID = '44787' +ChainType = 'celo' +FinalityDepth = 10 +LogPollInterval = '5s' +MinIncomingConfirmations = 1 +NoNewHeadsThreshold = '1m' +OCR.ContractConfirmations = 1 +NoNewFinalizedHeadsThreshold = '1m' + +[GasEstimator] +PriceDefault = '5 gwei' +PriceMax = '500 gwei' +PriceMin = '5 gwei' +BumpMin = '2 gwei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[HeadTracker] +HistoryDepth = 50 diff --git a/ccip/config/evm/Ethereum_Mainnet.toml b/ccip/config/evm/Ethereum_Mainnet.toml new file mode 100644 index 00000000000..0bcaf35c648 --- /dev/null +++ b/ccip/config/evm/Ethereum_Mainnet.toml @@ -0,0 +1,17 @@ +ChainID = '1' +LinkContractAddress = '0x514910771AF9Ca656af840dff83E8264EcF986CA' +MinContractPayment = '0.1 link' +OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A' +FinalityTagEnabled = true +NoNewFinalizedHeadsThreshold = '9m' + +[GasEstimator] +EIP1559DynamicFees = true + +[GasEstimator.BlockHistory] +# EIP-1559 does well on a smaller block history size +BlockHistorySize = 4 +TransactionPercentile = 50 + +[OCR2.Automation] +GasLimit = 10500000 diff --git a/ccip/config/evm/Ethereum_Sepolia.toml b/ccip/config/evm/Ethereum_Sepolia.toml new file mode 100644 index 00000000000..24a0e68f77a --- /dev/null +++ b/ccip/config/evm/Ethereum_Sepolia.toml @@ -0,0 +1,17 @@ +ChainID = '11155111' +LinkContractAddress = '0x779877A7B0D9E8603169DdbD7836e478b4624789' +MinContractPayment = '0.1 link' +FinalityTagEnabled = true + +[GasEstimator] +EIP1559DynamicFees = true + +[GasEstimator.BlockHistory] +BlockHistorySize = 4 +TransactionPercentile = 50 + +[OCR2.Automation] +GasLimit = 10500000 + +[HeadTracker] +FinalityTagBypass = false diff --git a/ccip/config/evm/Fantom_Mainnet.toml b/ccip/config/evm/Fantom_Mainnet.toml new file mode 100644 index 00000000000..7e76d94278d --- /dev/null +++ b/ccip/config/evm/Fantom_Mainnet.toml @@ -0,0 +1,12 @@ +ChainID = '250' +LinkContractAddress = '0x6F43FF82CCA38001B6699a8AC47A2d0E66939407' +LogPollInterval = '1s' +NoNewHeadsThreshold = '30s' +RPCBlockQueryDelay = 2 + +[GasEstimator] +# Fantom network has been slow to include txs at times when using the BlockHistory estimator, and the recommendation is to use SuggestedPrice mode. +Mode = 'SuggestedPrice' + +[OCR2.Automation] +GasLimit = 3800000 \ No newline at end of file diff --git a/ccip/config/evm/Fantom_Testnet.toml b/ccip/config/evm/Fantom_Testnet.toml new file mode 100644 index 00000000000..5f24a76c2e7 --- /dev/null +++ b/ccip/config/evm/Fantom_Testnet.toml @@ -0,0 +1,12 @@ +ChainID = '4002' +LinkContractAddress = '0xfaFedb041c0DD4fA2Dc0d87a6B0979Ee6FA7af5F' +LogPollInterval = '1s' +# Fantom testnet only emits blocks when a new tx is received, so this method of liveness detection is not useful +NoNewHeadsThreshold = '0' +RPCBlockQueryDelay = 2 + +[GasEstimator] +Mode = 'SuggestedPrice' + +[OCR2.Automation] +GasLimit = 3800000 \ No newline at end of file diff --git a/ccip/config/evm/Gnosis_Chiado.toml b/ccip/config/evm/Gnosis_Chiado.toml new file mode 100644 index 00000000000..379377a2266 --- /dev/null +++ b/ccip/config/evm/Gnosis_Chiado.toml @@ -0,0 +1,10 @@ +ChainID = '10200' +# Gnoisis Finality is approx 8 minutes @ 12 blocks per minute, so 96 blocks +FinalityDepth = 100 +ChainType = 'gnosis' +LogPollInterval = '5s' +NoNewFinalizedHeadsThreshold = '2m' + +[GasEstimator] +EIP1559DynamicFees = true +PriceMax = '500 gwei' diff --git a/ccip/config/evm/Gnosis_Mainnet.toml b/ccip/config/evm/Gnosis_Mainnet.toml new file mode 100644 index 00000000000..628646364f5 --- /dev/null +++ b/ccip/config/evm/Gnosis_Mainnet.toml @@ -0,0 +1,18 @@ +# xDai currently uses AuRa (like Parity) consensus so finality rules will be similar to parity +# See: https://www.poa.network/for-users/whitepaper/poadao-v1/proof-of-authority +# NOTE: xDai is planning to move to Honeybadger BFT which might have different finality guarantees +# https://www.xdaichain.com/for-validators/consensus/honeybadger-bft-consensus +# For worst case re-org depth on AuRa, assume 2n+2 (see: https://github.com/poanetwork/wiki/wiki/Aura-Consensus-Protocol-Audit) +# With xDai's current maximum of 19 validators then 40 blocks is the maximum possible re-org) +# The mainnet default of 50 blocks is ok here +ChainID = '100' +ChainType = 'gnosis' +LinkContractAddress = '0xE2e73A1c69ecF83F464EFCE6A5be353a37cA09b2' +LogPollInterval = '5s' +NoNewFinalizedHeadsThreshold = '2m' + +[GasEstimator] +PriceDefault = '1 gwei' +PriceMax = '500 gwei' +# 1 Gwei is the minimum accepted by the validators (unless whitelisted) +PriceMin = '1 gwei' diff --git a/ccip/config/evm/Kroma_Mainnet.toml b/ccip/config/evm/Kroma_Mainnet.toml new file mode 100644 index 00000000000..3a48aa8ae1b --- /dev/null +++ b/ccip/config/evm/Kroma_Mainnet.toml @@ -0,0 +1,27 @@ +ChainID = '255' +ChainType = 'kroma' # Kroma is based on the Optimism Bedrock architechture +FinalityDepth = 400 +FinalityTagEnabled = true +LogPollInterval = '2s' +NoNewHeadsThreshold = '40s' +MinIncomingConfirmations = 1 + +[GasEstimator] +EIP1559DynamicFees = true +PriceMin = '1 wei' +BumpMin = '100 wei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[Transactions] +ResendAfterThreshold = '30s' + +[HeadTracker] +HistoryDepth = 400 + +[NodePool] +SyncThreshold = 10 + +[OCR] +ContractConfirmations = 1 diff --git a/ccip/config/evm/Kroma_Sepolia.toml b/ccip/config/evm/Kroma_Sepolia.toml new file mode 100644 index 00000000000..9609a09e076 --- /dev/null +++ b/ccip/config/evm/Kroma_Sepolia.toml @@ -0,0 +1,27 @@ +ChainID = '2358' +ChainType = 'kroma' # Kroma is based on the Optimism Bedrock architechture +FinalityDepth = 400 +FinalityTagEnabled = true +LogPollInterval = '2s' +NoNewHeadsThreshold = '40s' +MinIncomingConfirmations = 1 + +[GasEstimator] +EIP1559DynamicFees = true +PriceMin = '1 wei' +BumpMin = '100 wei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[Transactions] +ResendAfterThreshold = '30s' + +[HeadTracker] +HistoryDepth = 400 + +[NodePool] +SyncThreshold = 10 + +[OCR] +ContractConfirmations = 1 diff --git a/ccip/config/evm/L3X_Mainnet.toml b/ccip/config/evm/L3X_Mainnet.toml new file mode 100644 index 00000000000..1fbda42fd2a --- /dev/null +++ b/ccip/config/evm/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/ccip/config/evm/L3X_Sepolia.toml b/ccip/config/evm/L3X_Sepolia.toml new file mode 100644 index 00000000000..ee515bb72ba --- /dev/null +++ b/ccip/config/evm/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/ccip/config/evm/Linea_Mainnet.toml b/ccip/config/evm/Linea_Mainnet.toml new file mode 100644 index 00000000000..94d8bedc44b --- /dev/null +++ b/ccip/config/evm/Linea_Mainnet.toml @@ -0,0 +1,17 @@ +ChainID = '59144' +# Block time 12s, finality < 60m +FinalityDepth = 300 +# Blocks are only emitted when a transaction happens / no empty blocks +NoNewHeadsThreshold = '0' + +[GasEstimator] +BumpPercent = 40 +PriceMin = '400 mwei' + +[Transactions] +# increase resend time to align with finality +ResendAfterThreshold = '3m' + +# set greater than finality depth +[HeadTracker] +HistoryDepth = 350 diff --git a/ccip/config/evm/Linea_Sepolia.toml b/ccip/config/evm/Linea_Sepolia.toml new file mode 100644 index 00000000000..ac5e18a09b6 --- /dev/null +++ b/ccip/config/evm/Linea_Sepolia.toml @@ -0,0 +1,13 @@ +ChainID = '59141' +FinalityDepth = 900 +NoNewHeadsThreshold = '0' + +[GasEstimator] +EIP1559DynamicFees = true +PriceMin = '1 wei' + +[Transactions] +ResendAfterThreshold = '3m' + +[HeadTracker] +HistoryDepth = 1000 \ No newline at end of file diff --git a/ccip/config/evm/Mantle_Sepolia.toml b/ccip/config/evm/Mantle_Sepolia.toml new file mode 100644 index 00000000000..ee994a71826 --- /dev/null +++ b/ccip/config/evm/Mantle_Sepolia.toml @@ -0,0 +1,19 @@ +ChainID = '5003' +ChainType = 'optimismBedrock' +FinalityDepth = 500 +LogPollInterval = '2s' +NoNewHeadsThreshold = '0' +MinIncomingConfirmations = 1 + +[HeadTracker] +HistoryDepth = 600 + +[GasEstimator] +Mode = 'L2Suggested' +PriceMax = '200 gwei' +LimitDefault = 100000000 +FeeCapDefault = '200 gwei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 200 +EIP1559FeeCapBufferBlocks = 0 \ No newline at end of file diff --git a/ccip/config/evm/Metis_Mainnet.toml b/ccip/config/evm/Metis_Mainnet.toml new file mode 100644 index 00000000000..f057400d014 --- /dev/null +++ b/ccip/config/evm/Metis_Mainnet.toml @@ -0,0 +1,21 @@ +# Metis is an L2 chain based on Optimism. +ChainID = '1088' +ChainType = 'metis' +# Sequencer offers absolute finality +FinalityDepth = 10 +FinalityTagEnabled = true +MinIncomingConfirmations = 1 +NoNewHeadsThreshold = '0' +OCR.ContractConfirmations = 1 + +[GasEstimator] +Mode = 'SuggestedPrice' +# Metis uses the SuggestedPrice estimator; we don't want to place any limits on the minimum gas price +PriceMin = '0' + +[GasEstimator.BlockHistory] +# Force an error if someone enables the estimator by accident; we never want to run the block history estimator on metisaa +BlockHistorySize = 0 + +[NodePool] +SyncThreshold = 10 diff --git a/ccip/config/evm/Metis_Sepolia.toml b/ccip/config/evm/Metis_Sepolia.toml new file mode 100644 index 00000000000..4ff4056c75d --- /dev/null +++ b/ccip/config/evm/Metis_Sepolia.toml @@ -0,0 +1,17 @@ +ChainID = '59902' +ChainType = 'optimismBedrock' +FinalityDepth = 10 +FinalityTagEnabled = true +MinIncomingConfirmations = 1 +NoNewHeadsThreshold = '0' +OCR.ContractConfirmations = 1 + +[GasEstimator] +Mode = 'SuggestedPrice' +PriceMin = '0' + +[GasEstimator.BlockHistory] +BlockHistorySize = 0 + +[NodePool] +SyncThreshold = 10 diff --git a/ccip/config/evm/Mode_Mainnet.toml b/ccip/config/evm/Mode_Mainnet.toml new file mode 100644 index 00000000000..69a8e93fecd --- /dev/null +++ b/ccip/config/evm/Mode_Mainnet.toml @@ -0,0 +1,30 @@ +ChainID = '34443' +FinalityDepth = 200 +FinalityTagEnabled = true +ChainType = 'optimismBedrock' + +[GasEstimator] +EIP1559DynamicFees = true +BumpThreshold = 60 +BumpPercent = 20 +BumpMin = '100 wei' +PriceMax = '120 gwei' +LimitDefault = 8000000 +FeeCapDefault = '120 gwei' + +[GasEstimator.BlockHistory] +# Default is 24, which leads to bumpy gas prices. In CCIP +# we want to smooth out the gas prices, so we increase the sample size. +BlockHistorySize = 200 +# The formula for FeeCap is (current block base fee * (1.125 ^ EIP1559FeeCapBufferBlocks) + tipcap) +# where tipcap is managed by the block history estimators. In the context of CCIP, +# the gas price is relayed to other changes for quotes so we want accurate/avg not pessimistic values. +# So we set this to zero so FeeCap = baseFee + tipcap. +EIP1559FeeCapBufferBlocks = 0 + +[HeadTracker] +HistoryDepth = 300 + +[NodePool] +PollFailureThreshold = 2 +PollInterval = '3s' diff --git a/ccip/config/evm/Mode_Sepolia.toml b/ccip/config/evm/Mode_Sepolia.toml new file mode 100644 index 00000000000..f7398869beb --- /dev/null +++ b/ccip/config/evm/Mode_Sepolia.toml @@ -0,0 +1,30 @@ +ChainID = '919' +FinalityDepth = 200 +FinalityTagEnabled = true +ChainType = 'optimismBedrock' + +[GasEstimator] +EIP1559DynamicFees = true +BumpThreshold = 60 +BumpPercent = 20 +BumpMin = '100 wei' +PriceMax = '120 gwei' +LimitDefault = 8000000 +FeeCapDefault = '120 gwei' + +[GasEstimator.BlockHistory] +# Default is 24, which leads to bumpy gas prices. In CCIP +# we want to smooth out the gas prices, so we increase the sample size. +BlockHistorySize = 200 +# The formula for FeeCap is (current block base fee * (1.125 ^ EIP1559FeeCapBufferBlocks) + tipcap) +# where tipcap is managed by the block history estimators. In the context of CCIP, +# the gas price is relayed to other changes for quotes so we want accurate/avg not pessimistic values. +# So we set this to zero so FeeCap = baseFee + tipcap. +EIP1559FeeCapBufferBlocks = 0 + +[HeadTracker] +HistoryDepth = 300 + +[NodePool] +PollFailureThreshold = 2 +PollInterval = '3s' diff --git a/ccip/config/evm/OKX_Mainnet.toml b/ccip/config/evm/OKX_Mainnet.toml new file mode 100644 index 00000000000..d0b26ede2e3 --- /dev/null +++ b/ccip/config/evm/OKX_Mainnet.toml @@ -0,0 +1 @@ +ChainID = '66' diff --git a/ccip/config/evm/OKX_Testnet.toml b/ccip/config/evm/OKX_Testnet.toml new file mode 100644 index 00000000000..2587f010b18 --- /dev/null +++ b/ccip/config/evm/OKX_Testnet.toml @@ -0,0 +1 @@ +ChainID = '65' diff --git a/ccip/config/evm/Optimism_Mainnet.toml b/ccip/config/evm/Optimism_Mainnet.toml new file mode 100644 index 00000000000..b0f56a49d90 --- /dev/null +++ b/ccip/config/evm/Optimism_Mainnet.toml @@ -0,0 +1,32 @@ +ChainID = '10' +ChainType = 'optimismBedrock' +FinalityDepth = 200 +FinalityTagEnabled = true +LinkContractAddress = '0x350a791Bfc2C21F9Ed5d10980Dad2e2638ffa7f6' +LogPollInterval = '2s' +NoNewHeadsThreshold = '40s' +MinIncomingConfirmations = 1 +NoNewFinalizedHeadsThreshold = '13m' + +[GasEstimator] +EIP1559DynamicFees = true +PriceMin = '1 wei' +BumpMin = '100 wei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[Transactions] +ResendAfterThreshold = '30s' + +[HeadTracker] +HistoryDepth = 300 + +[NodePool] +SyncThreshold = 10 + +[OCR] +ContractConfirmations = 1 + +[OCR2.Automation] +GasLimit = 6500000 diff --git a/ccip/config/evm/Optimism_Sepolia.toml b/ccip/config/evm/Optimism_Sepolia.toml new file mode 100644 index 00000000000..1c71aa5dd83 --- /dev/null +++ b/ccip/config/evm/Optimism_Sepolia.toml @@ -0,0 +1,31 @@ +ChainID = '11155420' +ChainType = 'optimismBedrock' +FinalityDepth = 200 +FinalityTagEnabled = true +LogPollInterval = '2s' +NoNewHeadsThreshold = '40s' +MinIncomingConfirmations = 1 +NoNewFinalizedHeadsThreshold = '15m' + +[GasEstimator] +EIP1559DynamicFees = true +PriceMin = '1 wei' +BumpMin = '100 wei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 60 + +[Transactions] +ResendAfterThreshold = '30s' + +[HeadTracker] +HistoryDepth = 300 + +[NodePool] +SyncThreshold = 10 + +[OCR] +ContractConfirmations = 1 + +[OCR2.Automation] +GasLimit = 6500000 diff --git a/ccip/config/evm/Polygon_Amoy.toml b/ccip/config/evm/Polygon_Amoy.toml new file mode 100644 index 00000000000..b05b3053a8e --- /dev/null +++ b/ccip/config/evm/Polygon_Amoy.toml @@ -0,0 +1,28 @@ +ChainID = '80002' +FinalityDepth = 500 +LogPollInterval = '1s' +MinIncomingConfirmations = 5 +NoNewHeadsThreshold = '30s' +RPCBlockQueryDelay = 10 +RPCDefaultBatchSize = 100 +NoNewFinalizedHeadsThreshold = '12m' + +[Transactions] +MaxQueued = 5000 + +[GasEstimator] +EIP1559DynamicFees = true +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceDefault = '25 gwei' +PriceMin = '25 gwei' +BumpMin = '20 gwei' +BumpThreshold = 5 + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[HeadTracker] +HistoryDepth = 2000 + +[NodePool] +SyncThreshold = 10 diff --git a/ccip/config/evm/Polygon_Mainnet.toml b/ccip/config/evm/Polygon_Mainnet.toml new file mode 100644 index 00000000000..bf605cab3c6 --- /dev/null +++ b/ccip/config/evm/Polygon_Mainnet.toml @@ -0,0 +1,38 @@ +# Polygon has a 1s block time and looser finality guarantees than ethereum. +ChainID = '137' +# It is quite common to see re-orgs on polygon go several hundred blocks deep. See: https://polygonscan.com/blocks_forked +FinalityDepth = 500 +FinalityTagEnabled = true +LinkContractAddress = '0xb0897686c545045aFc77CF20eC7A532E3120E0F1' +LogPollInterval = '1s' +MinIncomingConfirmations = 5 +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 +# Since re-orgs on Polygon can be so large, we need a large safety buffer to allow time for the queue to clear down before we start dropping transactions +MaxQueued = 5000 + +[GasEstimator] +# Many Polygon RPC providers set a minimum of 30 GWei on mainnet to prevent spam +PriceDefault = '30 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +# Many Polygon RPC providers set a minimum of 30 GWei on mainnet to prevent spam +PriceMin = '30 gwei' +BumpMin = '20 gwei' +# 10s delay since feeds update every minute in volatile situations +BumpThreshold = 5 + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[HeadTracker] +# Polygon suffers from a tremendous number of re-orgs, we need to set this to something very large to be conservative enough +HistoryDepth = 2000 + +[NodePool] +SyncThreshold = 10 diff --git a/ccip/config/evm/Polygon_Zkevm_Cardona.toml b/ccip/config/evm/Polygon_Zkevm_Cardona.toml new file mode 100644 index 00000000000..cd91465dae6 --- /dev/null +++ b/ccip/config/evm/Polygon_Zkevm_Cardona.toml @@ -0,0 +1,24 @@ +ChainID = '2442' +ChainType = 'zkevm' +FinalityDepth = 500 +NoNewHeadsThreshold = '12m' +MinIncomingConfirmations = 1 +LogPollInterval = '30s' +RPCDefaultBatchSize = 100 + +[OCR] +ContractConfirmations = 1 + +[Transactions] +ResendAfterThreshold = '3m' + +[GasEstimator] +PriceMin = '1 mwei' +BumpPercent = 40 +BumpMin = '20 mwei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 12 + +[HeadTracker] +HistoryDepth = 2000 diff --git a/ccip/config/evm/Polygon_Zkevm_Mainnet.toml b/ccip/config/evm/Polygon_Zkevm_Mainnet.toml new file mode 100644 index 00000000000..79e0cb0fce5 --- /dev/null +++ b/ccip/config/evm/Polygon_Zkevm_Mainnet.toml @@ -0,0 +1,26 @@ +ChainID = '1101' +ChainType = 'zkevm' +FinalityDepth = 500 +NoNewHeadsThreshold = '6m' +MinIncomingConfirmations = 1 +LogPollInterval = '30s' +RPCBlockQueryDelay = 15 +RPCDefaultBatchSize = 100 + +[OCR] +ContractConfirmations = 1 + +[Transactions] +ResendAfterThreshold = '3m' + +[GasEstimator] +PriceMin = '100 mwei' +BumpPercent = 40 +BumpMin = '100 mwei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 12 + +[HeadTracker] +# Polygon suffers from a tremendous number of re-orgs, we need to set this to something very large to be conservative enough +HistoryDepth = 2000 diff --git a/ccip/config/evm/Scroll_Mainnet.toml b/ccip/config/evm/Scroll_Mainnet.toml new file mode 100644 index 00000000000..4a887b504df --- /dev/null +++ b/ccip/config/evm/Scroll_Mainnet.toml @@ -0,0 +1,22 @@ +ChainID = '534352' +FinalityDepth = 10 +FinalityTagEnabled = true +ChainType = 'scroll' +LogPollInterval = '5s' +MinIncomingConfirmations = 1 +# Scroll only emits blocks when a new tx is received, so this method of liveness detection is not useful +NoNewHeadsThreshold = '0' + +[GasEstimator] +EIP1559DynamicFees = true +PriceMin = '1 wei' +BumpMin = '1 gwei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[HeadTracker] +HistoryDepth = 50 + +[OCR] +ContractConfirmations = 1 diff --git a/ccip/config/evm/Scroll_Sepolia.toml b/ccip/config/evm/Scroll_Sepolia.toml new file mode 100644 index 00000000000..b2e1cfbd733 --- /dev/null +++ b/ccip/config/evm/Scroll_Sepolia.toml @@ -0,0 +1,22 @@ +ChainID = '534351' +FinalityDepth = 10 +FinalityTagEnabled = true +ChainType = 'scroll' +LogPollInterval = '5s' +MinIncomingConfirmations = 1 +# Scroll only emits blocks when a new tx is received, so this method of liveness detection is not useful +NoNewHeadsThreshold = '0' + +[GasEstimator] +EIP1559DynamicFees = true +PriceMin = '1 wei' +BumpMin = '1 gwei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 24 + +[HeadTracker] +HistoryDepth = 50 + +[OCR] +ContractConfirmations = 1 diff --git a/ccip/config/evm/Simulated.toml b/ccip/config/evm/Simulated.toml new file mode 100644 index 00000000000..52e78c94edf --- /dev/null +++ b/ccip/config/evm/Simulated.toml @@ -0,0 +1,24 @@ +ChainID = '1337' +FinalityDepth = 10 +MinIncomingConfirmations = 1 +MinContractPayment = '100' +NoNewHeadsThreshold = '0s' + +[Transactions] +ReaperThreshold = '0s' +ResendAfterThreshold = '0s' + +[GasEstimator] +Mode = 'FixedPrice' +PriceMin = '0' +BumpThreshold = 0 +FeeCapDefault = '100 micro' +PriceMax = '100 micro' + +[HeadTracker] +HistoryDepth = 10 +MaxBufferSize = 100 +SamplingInterval = '0s' + +[OCR] +ContractConfirmations = 1 diff --git a/ccip/config/evm/WeMix_Mainnet.toml b/ccip/config/evm/WeMix_Mainnet.toml new file mode 100644 index 00000000000..7d3fcc6bc2b --- /dev/null +++ b/ccip/config/evm/WeMix_Mainnet.toml @@ -0,0 +1,16 @@ +ChainID = '1111' +ChainType = 'wemix' +FinalityDepth = 1 +FinalityTagEnabled = true +MinIncomingConfirmations = 1 +# WeMix emits a block every 1 second, regardless of transactions +LogPollInterval = '3s' +NoNewHeadsThreshold = '30s' +NoNewFinalizedHeadsThreshold = '40s' + +[OCR] +ContractConfirmations = 1 + +[GasEstimator] +EIP1559DynamicFees = true +TipCapDefault = '100 gwei' diff --git a/ccip/config/evm/WeMix_Testnet.toml b/ccip/config/evm/WeMix_Testnet.toml new file mode 100644 index 00000000000..5775097967a --- /dev/null +++ b/ccip/config/evm/WeMix_Testnet.toml @@ -0,0 +1,19 @@ +ChainID = '1112' +ChainType = 'wemix' +FinalityDepth = 1 +FinalityTagEnabled = true +MinIncomingConfirmations = 1 +# WeMix emits a block every 1 second, regardless of transactions +LogPollInterval = '3s' +NoNewHeadsThreshold = '30s' +NoNewFinalizedHeadsThreshold = '40s' + +[OCR] +ContractConfirmations = 1 + +[GasEstimator] +EIP1559DynamicFees = true +TipCapDefault = '100 gwei' + +[HeadTracker] +FinalityTagBypass = false diff --git a/ccip/config/evm/XLayer_Mainnet.toml b/ccip/config/evm/XLayer_Mainnet.toml new file mode 100644 index 00000000000..4096a4db244 --- /dev/null +++ b/ccip/config/evm/XLayer_Mainnet.toml @@ -0,0 +1,25 @@ +ChainID = '196' +ChainType = 'xlayer' +FinalityDepth = 500 +NoNewHeadsThreshold = '6m' +MinIncomingConfirmations = 1 +LogPollInterval = '30s' +RPCBlockQueryDelay = 15 +RPCDefaultBatchSize = 100 + +[OCR] +ContractConfirmations = 1 + +[Transactions] +ResendAfterThreshold = '3m' + +[GasEstimator] +PriceMin = '100 mwei' +BumpPercent = 40 +BumpMin = '100 mwei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 12 + +[HeadTracker] +HistoryDepth = 2000 diff --git a/ccip/config/evm/XLayer_Sepolia.toml b/ccip/config/evm/XLayer_Sepolia.toml new file mode 100644 index 00000000000..62e2c1e8ad0 --- /dev/null +++ b/ccip/config/evm/XLayer_Sepolia.toml @@ -0,0 +1,25 @@ +ChainID = '195' +ChainType = 'xlayer' +FinalityDepth = 500 +NoNewHeadsThreshold = '12m' +MinIncomingConfirmations = 1 +LogPollInterval = '30s' +RPCBlockQueryDelay = 15 +RPCDefaultBatchSize = 100 + +[OCR] +ContractConfirmations = 1 + +[Transactions] +ResendAfterThreshold = '3m' + +[GasEstimator] +PriceMin = '1 mwei' +BumpPercent = 40 +BumpMin = '20 mwei' + +[GasEstimator.BlockHistory] +BlockHistorySize = 12 + +[HeadTracker] +HistoryDepth = 2000 diff --git a/ccip/config/evm/zkSync_Mainnet.toml b/ccip/config/evm/zkSync_Mainnet.toml new file mode 100644 index 00000000000..a434cd38153 --- /dev/null +++ b/ccip/config/evm/zkSync_Mainnet.toml @@ -0,0 +1,28 @@ +ChainID = '324' +ChainType = 'zksync' +# 1200block ~ 20min concurrent with the l1_committed tag +FinalityDepth = 1200 +# block rate is ~2-5sec, so this ensures blocks are polled correctly +LogPollInterval = '5s' +# sufficient time for RPC to be labelled out of sync, since blockRate is pretty fast +NoNewHeadsThreshold = '1m' + +[GasEstimator] +# no EIP1559 to ensure our estimator doesnot estimate gas with MaxPriorityFee which will break minFunding requirement +EIP1559DynamicFees = false +# high LimitDefault for worst case pubdata bytes with BatchGasLimit reduced to 4M in OCR2Config +LimitDefault = 2_500_000_000 +FeeCapDefault = '500 mwei' +PriceDefault = '25 mwei' +# p999 value for gasPrice based on historical data +PriceMax = '500 mwei' +# avg gasPrices are at 0.025 gwei +PriceMin = '25 mwei' + +[GasEstimator.BlockHistory] +# increasing this to smooth out gas estimation +BlockHistorySize = 200 + +[HeadTracker] +# tracks top N blocks to keep in heads database table. Should store atleast the same # of blocks as finalityDepth +HistoryDepth = 1500 \ No newline at end of file diff --git a/ccip/config/evm/zkSync_Sepolia.toml b/ccip/config/evm/zkSync_Sepolia.toml new file mode 100644 index 00000000000..f3bc594886a --- /dev/null +++ b/ccip/config/evm/zkSync_Sepolia.toml @@ -0,0 +1,28 @@ +ChainID = '300' +ChainType = 'zksync' +# 200block ~ 20min concurrent with the l1_committed tag +FinalityDepth = 200 +# block rate is ~2-5sec, so this ensures blocks are polled correctly +LogPollInterval = '5s' +# sufficient time for RPC to be labelled out of sync, since blockRate is pretty fast +NoNewHeadsThreshold = '1m' + +[GasEstimator] +# no EIP1559 to ensure our estimator doesnot estimate gas with MaxPriorityFee which will break minFunding requirement +EIP1559DynamicFees = false +# high LimitDefault for worst case pubdata bytes with BatchGasLimit reduced to 4M in OCR2Config +LimitDefault = 2_500_000_000 +FeeCapDefault = '500 mwei' +PriceDefault = '25 mwei' +# p999 value for gasPrice based on historical data +PriceMax = '500 mwei' +# avg gasPrices are at 0.025 gwei +PriceMin = '25 mwei' + +[GasEstimator.BlockHistory] +# increasing this to smooth out gas estimation +BlockHistorySize = 200 + +[HeadTracker] +# tracks top N blocks to keep in heads database table. Should store atleast the same # of blocks as finalityDepth +HistoryDepth = 250 \ No newline at end of file diff --git a/core/chainlink.goreleaser.Dockerfile b/core/chainlink.goreleaser.Dockerfile index c35fe015cbd..c229ad488c3 100644 --- a/core/chainlink.goreleaser.Dockerfile +++ b/core/chainlink.goreleaser.Dockerfile @@ -38,6 +38,11 @@ RUN chmod +x /usr/local/bin/ldd_fix RUN /usr/local/bin/ldd_fix RUN apt-get remove -y patchelf +# CCIP specific +COPY ./cci[p]/confi[g] /chainlink/ccip-config +ARG CL_CHAIN_DEFAULTS +ENV CL_CHAIN_DEFAULTS=${CL_CHAIN_DEFAULTS} + RUN if [ ${CHAINLINK_USER} != root ]; then \ useradd --uid 14933 --create-home ${CHAINLINK_USER}; \ fi From ec585d45658014028ff06e0bc7b2d11aed2e56ce Mon Sep 17 00:00:00 2001 From: FelixFan1992 Date: Fri, 20 Sep 2024 12:31:34 -0400 Subject: [PATCH 18/20] devsvcs-514: update debugging script (#14502) --- core/scripts/chaincli/handler/debug.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index eac3233ea58..79dfc5d0182 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -43,7 +43,8 @@ import ( const ( ConditionTrigger uint8 = iota LogTrigger - expectedTypeAndVersion = "KeeperRegistry 2.1.0" + expectedVersion21 = "KeeperRegistry 2.1.0" + expectedVersion23 = "AutomationRegistry 2.3.0" ) var mercuryPacker = mercury.NewAbiPacker() @@ -85,8 +86,8 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if err != nil { failCheckConfig("failed to get typeAndVersion: make sure your registry contract address and archive node are valid", err) } - if typeAndVersion != expectedTypeAndVersion { - failCheckConfig(fmt.Sprintf("invalid registry contract: this command can only debug %s, got: %s", expectedTypeAndVersion, typeAndVersion), nil) + if typeAndVersion != expectedVersion21 && typeAndVersion != expectedVersion23 { + failCheckConfig(fmt.Sprintf("invalid registry contract: this command can only debug %s or %s, got: %s", expectedVersion21, expectedVersion23, typeAndVersion), nil) } // get upkeepID from command args upkeepID := big.NewInt(0) From 85a8d09845d6bd30f62b1de4bf8c62f3a77a6c8e Mon Sep 17 00:00:00 2001 From: Simson Date: Fri, 20 Sep 2024 23:31:52 +0530 Subject: [PATCH 19/20] Hedera int with TXM fixes & config (#14129) * re-changes on top of develop * Docs update * changeset * merged the error tests & Config fix * Apply suggestions from code review Co-authored-by: Jordan Krage * added newly found error * formatting * formatting * updated docs * Updating config to run with multiple RPCs * bump seth to v1.2.2 * updated configs --------- Co-authored-by: Jordan Krage Co-authored-by: davidcauchi --- .changeset/many-lamps-rush.md | 5 + core/chains/evm/client/errors.go | 12 +- core/chains/evm/client/errors_test.go | 7 + .../config/toml/defaults/Hedera_Mainnet.toml | 31 +++ .../config/toml/defaults/Hedera_Testnet.toml | 31 +++ docs/CONFIG.md | 204 ++++++++++++++++++ 6 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 .changeset/many-lamps-rush.md create mode 100644 core/chains/evm/config/toml/defaults/Hedera_Mainnet.toml create mode 100644 core/chains/evm/config/toml/defaults/Hedera_Testnet.toml diff --git a/.changeset/many-lamps-rush.md b/.changeset/many-lamps-rush.md new file mode 100644 index 00000000000..93d779aec95 --- /dev/null +++ b/.changeset/many-lamps-rush.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#added Hedera configs diff --git a/core/chains/evm/client/errors.go b/core/chains/evm/client/errors.go index 6882cca524f..ba13e1bfea8 100644 --- a/core/chains/evm/client/errors.go +++ b/core/chains/evm/client/errors.go @@ -267,6 +267,16 @@ var mantle = ClientErrors{ Fatal: regexp.MustCompile(`(: |^)'*invalid sender`), } +var hederaFatal = regexp.MustCompile(`(: |^)(execution reverted)(:|$) | ^Transaction gas limit '(\d+)' exceeds block gas limit '(\d+)' | ^Transaction gas limit provided '(\d+)' is insufficient of intrinsic gas required '(\d+)' | ^Oversized data:|status INVALID_SIGNATURE`) +var hedera = ClientErrors{ + NonceTooLow: regexp.MustCompile(`Nonce too low`), + NonceTooHigh: regexp.MustCompile(`Nonce too high`), + TerminallyUnderpriced: regexp.MustCompile(`(Gas price '(\d+)' is below configured minimum gas price '(\d+)')|(Gas price too low)`), + InsufficientEth: regexp.MustCompile(`Insufficient funds for transfer| failed precheck with status INSUFFICIENT_PAYER_BALANCE`), + ServiceUnavailable: regexp.MustCompile(`Transaction execution returns a null value for transaction`), + Fatal: hederaFatal, +} + var gnosis = ClientErrors{ TransactionAlreadyInMempool: regexp.MustCompile(`(: |^)(alreadyknown)`), } @@ -278,7 +288,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, treasure, mantle, aStar, gnosis, internal} +var clients = []ClientErrors{parity, geth, arbitrum, metis, substrate, avalanche, nethermind, harmony, besu, erigon, klaytn, celo, zkSync, zkEvm, treasure, mantle, aStar, hedera, gnosis, internal} // ClientErrorRegexes returns a map of compiled regexes for each error type func ClientErrorRegexes(errsRegex config.ClientErrors) *ClientErrors { diff --git a/core/chains/evm/client/errors_test.go b/core/chains/evm/client/errors_test.go index e6478060917..84e518db666 100644 --- a/core/chains/evm/client/errors_test.go +++ b/core/chains/evm/client/errors_test.go @@ -46,6 +46,7 @@ func Test_Eth_Errors(t *testing.T) { {"call failed: OldNonce, Current nonce: 22, nonce of rejected tx: 17", true, "Nethermind"}, {"nonce too low. allowed nonce range: 427 - 447, actual: 426", true, "zkSync"}, {"client error nonce too low", true, "tomlConfig"}, + {"[Request ID: 2e952947-ffad-408b-aed9-35f3ed152001] Nonce too low. Provided nonce: 15, current nonce: 15", true, "hedera"}, } for _, test := range tests { @@ -67,6 +68,7 @@ func Test_Eth_Errors(t *testing.T) { {"nonce too high", true, "Erigon"}, {"nonce too high. allowed nonce range: 427 - 477, actual: 527", true, "zkSync"}, {"client error nonce too high", true, "tomlConfig"}, + {"[Request ID: 3ec591b4-9396-49f4-a03f-06c415a7cc6a] Nonce too high. Provided nonce: 16, current nonce: 15", true, "hedera"}, } for _, test := range tests { @@ -170,6 +172,7 @@ func Test_Eth_Errors(t *testing.T) { {"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"}, + {"[Request ID: e4d09e44-19a4-4eb7-babe-270db4c2ebc9] Gas price '830000000000' is below configured minimum gas price '950000000000'", true, "hedera"}, } for _, test := range tests { @@ -219,6 +222,8 @@ func Test_Eth_Errors(t *testing.T) { {"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"}, + {"[Request ID: 9dd78806-58c8-4e6d-89a8-a60962abe705] Error invoking RPC: transaction 0.0.3041916@1717691931.680570179 failed precheck with status INSUFFICIENT_PAYER_BALANCE", true, "hedera"}, + {"[Request ID: 6198d2a3-590f-4724-aae5-69fecead0c49] Insufficient funds for transfer", true, "hedera"}, } for _, test := range tests { err = evmclient.NewSendErrorS(test.message) @@ -235,6 +240,7 @@ func Test_Eth_Errors(t *testing.T) { {"i/o timeout", true, "Arbitrum"}, {"network is unreachable", true, "Arbitrum"}, {"client error service unavailable", true, "tomlConfig"}, + {"[Request ID: 825608a8-fd8a-4b5b-aea7-92999509306d] Error invoking RPC: [Request ID: 825608a8-fd8a-4b5b-aea7-92999509306d] Transaction execution returns a null value for transaction", true, "hedera"}, } for _, test := range tests { err = evmclient.NewSendErrorS(test.message) @@ -409,6 +415,7 @@ func Test_Eth_Errors_Fatal(t *testing.T) { {"failed to forward tx to sequencer, please try again. Error message: 'invalid sender'", true, "Mantle"}, {"client error fatal", true, "tomlConfig"}, + {"[Request ID: d9711488-4c1e-4af2-bc1f-7969913d7b60] Error invoking RPC: transaction 0.0.4425573@1718213476.914320044 failed precheck with status INVALID_SIGNATURE", true, "hedera"}, {"invalid chain id for signer", true, "Treasure"}, } diff --git a/core/chains/evm/config/toml/defaults/Hedera_Mainnet.toml b/core/chains/evm/config/toml/defaults/Hedera_Mainnet.toml new file mode 100644 index 00000000000..4d5e48816fa --- /dev/null +++ b/core/chains/evm/config/toml/defaults/Hedera_Mainnet.toml @@ -0,0 +1,31 @@ +ChainID = '295' +ChainType = 'hedera' +# Considering the 3-5 (6 including a buffer) seconds of finality and 2 seconds block production +# We set the depth to 6/2 = 3 blocks, setting to 10 for safety +FinalityDepth = 10 +# Hedera has high TPS, so polling less often +LogPollInterval = '10s' +MinIncomingConfirmations = 1 + +[BalanceMonitor] +Enabled = true + +[GasEstimator] +Mode = 'SuggestedPrice' +# Since Hedera dont have mempool and there's no way for a node to front run or a user to bribe a node to submit the transaction earlier than it's consensus timestamp, +# But they have automated congesting pricing throttling which would mean at high sustained level the gasPrice itself could be increased to prevent malicious behaviour. +# Disabling the Bumpthreshold as TXM now implicity handles the bumping after checking on-chain nonce & re-broadcast for Hedera chain type +BumpThreshold = 0 +BumpMin = '10 gwei' +BumpPercent = 20 + +[Transactions] +# To hit throttling you'd need to maintain 15 m gas /sec over a prolonged period of time. +# Because Hedera's block times are every 2 secs it's less less likely to happen as compared to other chains +# Setting this to little higher even though Hedera has High TPS, We have seen 10-12s to get the trasaction mined & 20-25s incase of failures +# Accounting for Node syncs & avoid re-sending txns before fetching the receipt, setting to 2m +ResendAfterThreshold = '2m' + + +[NodePool] +SyncThreshold = 10 \ No newline at end of file diff --git a/core/chains/evm/config/toml/defaults/Hedera_Testnet.toml b/core/chains/evm/config/toml/defaults/Hedera_Testnet.toml new file mode 100644 index 00000000000..6086a43af2c --- /dev/null +++ b/core/chains/evm/config/toml/defaults/Hedera_Testnet.toml @@ -0,0 +1,31 @@ +ChainID = '296' +ChainType = 'hedera' +# Considering the 3-5 (6 including a buffer) seconds of finality and 2 seconds block production +# We set the depth to 6/2 = 3 blocks, setting to 10 for safety +FinalityDepth = 10 +# Hedera has high TPS, so polling less often +LogPollInterval = '10s' +MinIncomingConfirmations = 1 + +[BalanceMonitor] +Enabled = true + +[GasEstimator] +Mode = 'SuggestedPrice' +# Since Hedera dont have mempool and there's no way for a node to front run or a user to bribe a node to submit the transaction earlier than it's consensus timestamp, +# But they have automated congesting pricing throttling which would mean at high sustained level the gasPrice itself could be increased to prevent malicious behaviour. +# Disabling the Bumpthreshold as TXM now implicity handles the bumping after checking on-chain nonce & re-broadcast for Hedera chain type +BumpThreshold = 0 +BumpMin = '10 gwei' +BumpPercent = 20 + +[Transactions] +# To hit throttling you'd need to maintain 15 m gas /sec over a prolonged period of time. +# Because Hedera's block times are every 2 secs it's less less likely to happen as compared to other chains +# Setting this to little higher even though Hedera has High TPS, We have seen 10-12s to get the trasaction mined & 20-25s incase of failures +# Accounting for Node syncs & avoid re-sending txns before fetching the receipt, setting to 2m +ResendAfterThreshold = '2m' + + +[NodePool] +SyncThreshold = 10 \ No newline at end of file diff --git a/docs/CONFIG.md b/docs/CONFIG.md index c9262577f10..c3eeaac2827 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -4000,6 +4000,210 @@ GasLimitDefault = 400000

+
Hedera Mainnet (295)

+ +```toml +AutoCreateKey = true +BlockBackfillDepth = 10 +BlockBackfillSkip = false +ChainType = 'hedera' +FinalityDepth = 10 +FinalityTagEnabled = false +LogBackfillBatchSize = 1000 +LogPollInterval = '10s' +LogKeepBlocksDepth = 100000 +LogPrunePageSize = 0 +BackupLogPollerBlockDelay = 100 +MinIncomingConfirmations = 1 +MinContractPayment = '0.00001 link' +NonceAutoSync = true +NoNewHeadsThreshold = '3m0s' +LogBroadcasterEnabled = true +RPCDefaultBatchSize = 250 +RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 +NoNewFinalizedHeadsThreshold = '0s' + +[Transactions] +ForwardersEnabled = false +MaxInFlight = 16 +MaxQueued = 250 +ReaperInterval = '1h0m0s' +ReaperThreshold = '168h0m0s' +ResendAfterThreshold = '2m0s' + +[Transactions.AutoPurge] +Enabled = false + +[BalanceMonitor] +Enabled = true + +[GasEstimator] +Mode = 'SuggestedPrice' +PriceDefault = '20 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '1 gwei' +LimitDefault = 500000 +LimitMax = 500000 +LimitMultiplier = '1' +LimitTransfer = 21000 +EstimateLimit = false +BumpMin = '10 gwei' +BumpPercent = 20 +BumpThreshold = 0 +EIP1559DynamicFees = false +FeeCapDefault = '100 gwei' +TipCapDefault = '1 wei' +TipCapMin = '1 wei' + +[GasEstimator.BlockHistory] +BatchSize = 25 +BlockHistorySize = 8 +CheckInclusionBlocks = 12 +CheckInclusionPercentile = 90 +TransactionPercentile = 60 + +[GasEstimator.FeeHistory] +CacheTimeout = '10s' + +[HeadTracker] +HistoryDepth = 100 +MaxBufferSize = 3 +SamplingInterval = '1s' +MaxAllowedFinalityDepth = 10000 +FinalityTagBypass = true + +[NodePool] +PollFailureThreshold = 5 +PollInterval = '10s' +SelectionMode = 'HighestHead' +SyncThreshold = 10 +LeaseDuration = '0s' +NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' + +[OCR] +ContractConfirmations = 4 +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' +ObservationGracePeriod = '1s' + +[OCR2] +[OCR2.Automation] +GasLimit = 5400000 + +[Workflow] +GasLimitDefault = 400000 +``` + +

+ +
Hedera Testnet (296)

+ +```toml +AutoCreateKey = true +BlockBackfillDepth = 10 +BlockBackfillSkip = false +ChainType = 'hedera' +FinalityDepth = 10 +FinalityTagEnabled = false +LogBackfillBatchSize = 1000 +LogPollInterval = '10s' +LogKeepBlocksDepth = 100000 +LogPrunePageSize = 0 +BackupLogPollerBlockDelay = 100 +MinIncomingConfirmations = 1 +MinContractPayment = '0.00001 link' +NonceAutoSync = true +NoNewHeadsThreshold = '3m0s' +LogBroadcasterEnabled = true +RPCDefaultBatchSize = 250 +RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 +NoNewFinalizedHeadsThreshold = '0s' + +[Transactions] +ForwardersEnabled = false +MaxInFlight = 16 +MaxQueued = 250 +ReaperInterval = '1h0m0s' +ReaperThreshold = '168h0m0s' +ResendAfterThreshold = '2m0s' + +[Transactions.AutoPurge] +Enabled = false + +[BalanceMonitor] +Enabled = true + +[GasEstimator] +Mode = 'SuggestedPrice' +PriceDefault = '20 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '1 gwei' +LimitDefault = 500000 +LimitMax = 500000 +LimitMultiplier = '1' +LimitTransfer = 21000 +EstimateLimit = false +BumpMin = '10 gwei' +BumpPercent = 20 +BumpThreshold = 0 +EIP1559DynamicFees = false +FeeCapDefault = '100 gwei' +TipCapDefault = '1 wei' +TipCapMin = '1 wei' + +[GasEstimator.BlockHistory] +BatchSize = 25 +BlockHistorySize = 8 +CheckInclusionBlocks = 12 +CheckInclusionPercentile = 90 +TransactionPercentile = 60 + +[GasEstimator.FeeHistory] +CacheTimeout = '10s' + +[HeadTracker] +HistoryDepth = 100 +MaxBufferSize = 3 +SamplingInterval = '1s' +MaxAllowedFinalityDepth = 10000 +FinalityTagBypass = true + +[NodePool] +PollFailureThreshold = 5 +PollInterval = '10s' +SelectionMode = 'HighestHead' +SyncThreshold = 10 +LeaseDuration = '0s' +NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' + +[OCR] +ContractConfirmations = 4 +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' +ObservationGracePeriod = '1s' + +[OCR2] +[OCR2.Automation] +GasLimit = 5400000 + +[Workflow] +GasLimitDefault = 400000 +``` + +

+
zkSync Sepolia (300)

```toml From 10f7aabc2972615cae4edd8f3532ad6aea521cee Mon Sep 17 00:00:00 2001 From: Austin Born Date: Fri, 20 Sep 2024 11:31:07 -0700 Subject: [PATCH 20/20] DF-20372 (pt 2): Update Streams PluginConfig checks and FeedID parsing (#14504) * Update Streams PluginConfig checks and FeedID parsing * Update changeset comment * Linting fixes * Update v4/data_source_test.go * Pull out duplicate code into helper --- .changeset/thirty-emus-enjoy.md | 7 +++ core/services/ocr2/delegate.go | 4 +- core/services/ocr2/plugins/mercury/plugin.go | 30 +++++++--- core/services/ocr2/validate/validate.go | 2 +- .../services/relay/evm/mercury/utils/feeds.go | 3 + .../relay/evm/mercury/utils/feeds_test.go | 55 +++++++++++++------ .../relay/evm/mercury/v2/data_source.go | 12 +--- .../relay/evm/mercury/v2/data_source_test.go | 4 +- .../relay/evm/mercury/v3/data_source.go | 12 +--- .../relay/evm/mercury/v3/data_source_test.go | 4 +- .../relay/evm/mercury/v4/data_source.go | 8 ++- .../relay/evm/mercury/v4/data_source_test.go | 31 ++++++++++- 12 files changed, 118 insertions(+), 54 deletions(-) create mode 100644 .changeset/thirty-emus-enjoy.md diff --git a/.changeset/thirty-emus-enjoy.md b/.changeset/thirty-emus-enjoy.md new file mode 100644 index 00000000000..4fbe030ec59 --- /dev/null +++ b/.changeset/thirty-emus-enjoy.md @@ -0,0 +1,7 @@ +--- +"chainlink": minor +--- + +#bugfix Fix potential nil ptr reference for LinkFeedID and NativeFeedID in Mercury specs +#bugfix Ensure Streams PluginConfig is checked for contents correctly when validated +#changed New Feed IDs with 0x01 prefix can be parsed for Mercury report schemas diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 9d4dbb85982..b51765f06f7 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -889,10 +889,10 @@ func (d *Delegate) newServicesMercury( } var telemetryType synchronization.TelemetryType - if relayConfig.EnableTriggerCapability && jb.OCR2OracleSpec.PluginConfig == nil { + if relayConfig.EnableTriggerCapability && len(jb.OCR2OracleSpec.PluginConfig) == 0 { telemetryType = synchronization.OCR3DataFeeds // First use case for TriggerCapability transmission is Data Feeds, so telemetry should be routed accordingly. - // This is only true if TriggerCapability is the *only* transmission method (PluginConfig == nil). + // This is only true if TriggerCapability is the *only* transmission method (PluginConfig is empty). } else { telemetryType = synchronization.OCR3Mercury } diff --git a/core/services/ocr2/plugins/mercury/plugin.go b/core/services/ocr2/plugins/mercury/plugin.go index f78531d6b07..8a4101804dd 100644 --- a/core/services/ocr2/plugins/mercury/plugin.go +++ b/core/services/ocr2/plugins/mercury/plugin.go @@ -81,7 +81,7 @@ func NewServices( var err error var pluginConfig config.PluginConfig - if jb.OCR2OracleSpec.PluginConfig == nil { + if len(jb.OCR2OracleSpec.PluginConfig) == 0 { if !enableTriggerCapability { return nil, fmt.Errorf("at least one transmission option must be configured") } @@ -180,10 +180,22 @@ type factoryCfg struct { feedID utils.FeedID } +func getPluginFeedIDs(pluginConfig config.PluginConfig) (linkFeedID utils.FeedID, nativeFeedID utils.FeedID) { + if pluginConfig.LinkFeedID != nil { + linkFeedID = *pluginConfig.LinkFeedID + } + if pluginConfig.NativeFeedID != nil { + nativeFeedID = *pluginConfig.NativeFeedID + } + return linkFeedID, nativeFeedID +} + func newv4factory(factoryCfg factoryCfg) (ocr3types.MercuryPluginFactory, []job.ServiceCtx, error) { var factory ocr3types.MercuryPluginFactory srvs := make([]job.ServiceCtx, 0) + linkFeedID, nativeFeedID := getPluginFeedIDs(factoryCfg.reportingPluginConfig) + ds := mercuryv4.NewDataSource( factoryCfg.orm, factoryCfg.pipelineRunner, @@ -194,8 +206,8 @@ func newv4factory(factoryCfg factoryCfg) (ocr3types.MercuryPluginFactory, []job. factoryCfg.saver, factoryCfg.chEnhancedTelem, factoryCfg.ocr2Provider.MercuryServerFetcher(), - *factoryCfg.reportingPluginConfig.LinkFeedID, - *factoryCfg.reportingPluginConfig.NativeFeedID, + linkFeedID, + nativeFeedID, ) loopCmd := env.MercuryPlugin.Cmd.Get() @@ -221,6 +233,8 @@ func newv3factory(factoryCfg factoryCfg) (ocr3types.MercuryPluginFactory, []job. var factory ocr3types.MercuryPluginFactory srvs := make([]job.ServiceCtx, 0) + linkFeedID, nativeFeedID := getPluginFeedIDs(factoryCfg.reportingPluginConfig) + ds := mercuryv3.NewDataSource( factoryCfg.orm, factoryCfg.pipelineRunner, @@ -231,8 +245,8 @@ func newv3factory(factoryCfg factoryCfg) (ocr3types.MercuryPluginFactory, []job. factoryCfg.saver, factoryCfg.chEnhancedTelem, factoryCfg.ocr2Provider.MercuryServerFetcher(), - *factoryCfg.reportingPluginConfig.LinkFeedID, - *factoryCfg.reportingPluginConfig.NativeFeedID, + linkFeedID, + nativeFeedID, ) loopCmd := env.MercuryPlugin.Cmd.Get() @@ -258,6 +272,8 @@ func newv2factory(factoryCfg factoryCfg) (ocr3types.MercuryPluginFactory, []job. var factory ocr3types.MercuryPluginFactory srvs := make([]job.ServiceCtx, 0) + linkFeedID, nativeFeedID := getPluginFeedIDs(factoryCfg.reportingPluginConfig) + ds := mercuryv2.NewDataSource( factoryCfg.orm, factoryCfg.pipelineRunner, @@ -268,8 +284,8 @@ func newv2factory(factoryCfg factoryCfg) (ocr3types.MercuryPluginFactory, []job. factoryCfg.saver, factoryCfg.chEnhancedTelem, factoryCfg.ocr2Provider.MercuryServerFetcher(), - *factoryCfg.reportingPluginConfig.LinkFeedID, - *factoryCfg.reportingPluginConfig.NativeFeedID, + linkFeedID, + nativeFeedID, ) loopCmd := env.MercuryPlugin.Cmd.Get() diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go index 09b974d4e30..7ea34e5ac2d 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -304,7 +304,7 @@ func validateOCR2MercurySpec(spec *job.OCR2OracleSpec, feedID [32]byte) error { return pkgerrors.Wrap(err, "error while unmarshalling relay config") } - if spec.PluginConfig == nil { + if len(spec.PluginConfig) == 0 { if !relayConfig.EnableTriggerCapability { return pkgerrors.Wrap(err, "at least one transmission option must be configured") } diff --git a/core/services/relay/evm/mercury/utils/feeds.go b/core/services/relay/evm/mercury/utils/feeds.go index 36d6bc60f58..eb4f6850221 100644 --- a/core/services/relay/evm/mercury/utils/feeds.go +++ b/core/services/relay/evm/mercury/utils/feeds.go @@ -104,7 +104,10 @@ func (f *FeedID) UnmarshalText(input []byte) error { func (f FeedID) Version() FeedVersion { if _, exists := legacyV1FeedIDM[f]; exists { return REPORT_V1 + } else if f[0] == 0x01 { // Keystone Feed IDs + return FeedVersion(binary.BigEndian.Uint16(f[5:7])) } + return FeedVersion(binary.BigEndian.Uint16(f[:2])) } diff --git a/core/services/relay/evm/mercury/utils/feeds_test.go b/core/services/relay/evm/mercury/utils/feeds_test.go index 37b9b47de76..d6db7a4a8c4 100644 --- a/core/services/relay/evm/mercury/utils/feeds_test.go +++ b/core/services/relay/evm/mercury/utils/feeds_test.go @@ -7,27 +7,48 @@ import ( ) var ( - v1FeedId = (FeedID)([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 = (FeedID)([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 = (FeedID)([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}) + v1FeedID = (FeedID)([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 = (FeedID)([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 = (FeedID)([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}) + keystonev2Feed = (FeedID)([32]uint8{01, 12, 34, 56, 78, 00, 02, 04, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00}) + keystonev3Feed = (FeedID)([32]uint8{01, 12, 34, 56, 78, 00, 03, 04, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00}) + keystonev4Feed = (FeedID)([32]uint8{01, 12, 34, 56, 78, 00, 04, 04, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00}) ) func Test_FeedID_Version(t *testing.T) { t.Run("versioned feed ID", func(t *testing.T) { - assert.Equal(t, REPORT_V1, v1FeedId.Version()) - assert.True(t, v1FeedId.IsV1()) - assert.False(t, v1FeedId.IsV2()) - assert.False(t, v1FeedId.IsV3()) - - assert.Equal(t, REPORT_V2, v2FeedId.Version()) - assert.False(t, v2FeedId.IsV1()) - assert.True(t, v2FeedId.IsV2()) - assert.False(t, v2FeedId.IsV3()) - - assert.Equal(t, REPORT_V3, v3FeedId.Version()) - assert.False(t, v3FeedId.IsV1()) - assert.False(t, v3FeedId.IsV2()) - assert.True(t, v3FeedId.IsV3()) + assert.Equal(t, REPORT_V1, v1FeedID.Version()) + assert.True(t, v1FeedID.IsV1()) + assert.False(t, v1FeedID.IsV2()) + assert.False(t, v1FeedID.IsV3()) + + assert.Equal(t, REPORT_V2, v2FeedID.Version()) + assert.False(t, v2FeedID.IsV1()) + assert.True(t, v2FeedID.IsV2()) + assert.False(t, v2FeedID.IsV3()) + + assert.Equal(t, REPORT_V3, v3FeedID.Version()) + assert.False(t, v3FeedID.IsV1()) + assert.False(t, v3FeedID.IsV2()) + assert.True(t, v3FeedID.IsV3()) + + assert.Equal(t, REPORT_V2, keystonev2Feed.Version()) + assert.False(t, keystonev2Feed.IsV1()) + assert.True(t, keystonev2Feed.IsV2()) + assert.False(t, keystonev2Feed.IsV3()) + assert.False(t, keystonev2Feed.IsV4()) + + assert.Equal(t, REPORT_V3, keystonev3Feed.Version()) + assert.False(t, keystonev3Feed.IsV1()) + assert.False(t, keystonev3Feed.IsV2()) + assert.True(t, keystonev3Feed.IsV3()) + assert.False(t, keystonev3Feed.IsV4()) + + assert.Equal(t, REPORT_V4, keystonev4Feed.Version()) + assert.False(t, keystonev4Feed.IsV1()) + assert.False(t, keystonev4Feed.IsV2()) + assert.False(t, keystonev4Feed.IsV3()) + assert.True(t, keystonev4Feed.IsV4()) }) t.Run("legacy special cases", func(t *testing.T) { for _, feedID := range legacyV1FeedIDs { diff --git a/core/services/relay/evm/mercury/v2/data_source.go b/core/services/relay/evm/mercury/v2/data_source.go index d05bd00e25a..fed748ac937 100644 --- a/core/services/relay/evm/mercury/v2/data_source.go +++ b/core/services/relay/evm/mercury/v2/data_source.go @@ -2,7 +2,6 @@ package v2 import ( "context" - "encoding/json" "fmt" "math/big" "sync" @@ -23,7 +22,6 @@ import ( 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/v2/reportcodec" - relayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -63,12 +61,6 @@ func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs v2types.Observation, pipelineExecutionErr error) { var wg sync.WaitGroup - var relayConfig relayTypes.RelayConfig - err := json.Unmarshal(ds.jb.OCR2OracleSpec.RelayConfig.Bytes(), &relayConfig) - if err != nil { - pipelineExecutionErr = fmt.Errorf("failed to deserialize relay config: %w", err) - return - } ctx, cancel := context.WithCancel(ctx) if fetchMaxFinalizedTimestamp { @@ -116,7 +108,7 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam }() var isLink, isNative bool - if ds.jb.OCR2OracleSpec.PluginConfig == nil { + if len(ds.jb.OCR2OracleSpec.PluginConfig) == 0 { obs.LinkPrice.Val = v2.MissingPrice } else if ds.feedID == ds.linkFeedID { isLink = true @@ -136,7 +128,7 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam }() } - if ds.jb.OCR2OracleSpec.PluginConfig == nil { + if len(ds.jb.OCR2OracleSpec.PluginConfig) == 0 { obs.NativePrice.Val = v2.MissingPrice } else if ds.feedID == ds.nativeFeedID { isNative = true diff --git a/core/services/relay/evm/mercury/v2/data_source_test.go b/core/services/relay/evm/mercury/v2/data_source_test.go index 7392ceb9866..25716521d86 100644 --- a/core/services/relay/evm/mercury/v2/data_source_test.go +++ b/core/services/relay/evm/mercury/v2/data_source_test.go @@ -284,7 +284,7 @@ func Test_Datasource(t *testing.T) { assert.EqualError(t, obs.NativePrice.Err, "some error fetching native price") }) - t.Run("when PluginConfig=nil skips fetching link and native prices", func(t *testing.T) { + t.Run("when PluginConfig is empty", func(t *testing.T) { t.Cleanup(func() { ds.jb = jb }) @@ -292,7 +292,7 @@ func Test_Datasource(t *testing.T) { fetcher.linkPriceErr = errors.New("some error fetching link price") fetcher.nativePriceErr = errors.New("some error fetching native price") - ds.jb.OCR2OracleSpec.PluginConfig = nil + ds.jb.OCR2OracleSpec.PluginConfig = job.JSONConfig{} obs, err := ds.Observe(ctx, repts, false) assert.NoError(t, err) diff --git a/core/services/relay/evm/mercury/v3/data_source.go b/core/services/relay/evm/mercury/v3/data_source.go index 48db946517f..9744ec45d80 100644 --- a/core/services/relay/evm/mercury/v3/data_source.go +++ b/core/services/relay/evm/mercury/v3/data_source.go @@ -2,7 +2,6 @@ package v3 import ( "context" - "encoding/json" "errors" "fmt" "math/big" @@ -23,7 +22,6 @@ import ( 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/v3/reportcodec" - relayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -65,12 +63,6 @@ func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs v3types.Observation, pipelineExecutionErr error) { var wg sync.WaitGroup - var relayConfig relayTypes.RelayConfig - err := json.Unmarshal(ds.jb.OCR2OracleSpec.RelayConfig.Bytes(), &relayConfig) - if err != nil { - pipelineExecutionErr = fmt.Errorf("failed to deserialize relay config: %w", err) - return - } ctx, cancel := context.WithCancel(ctx) if fetchMaxFinalizedTimestamp { @@ -120,7 +112,7 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam }() var isLink, isNative bool - if ds.jb.OCR2OracleSpec.PluginConfig == nil { + if len(ds.jb.OCR2OracleSpec.PluginConfig) == 0 { obs.LinkPrice.Val = v3.MissingPrice } else if ds.feedID == ds.linkFeedID { isLink = true @@ -140,7 +132,7 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam }() } - if ds.jb.OCR2OracleSpec.PluginConfig == nil { + if len(ds.jb.OCR2OracleSpec.PluginConfig) == 0 { obs.NativePrice.Val = v3.MissingPrice } else if ds.feedID == ds.nativeFeedID { isNative = true diff --git a/core/services/relay/evm/mercury/v3/data_source_test.go b/core/services/relay/evm/mercury/v3/data_source_test.go index 3d01d7472e5..518fabb12c9 100644 --- a/core/services/relay/evm/mercury/v3/data_source_test.go +++ b/core/services/relay/evm/mercury/v3/data_source_test.go @@ -364,7 +364,7 @@ func Test_Datasource(t *testing.T) { assert.EqualError(t, obs.NativePrice.Err, "some error fetching native price") }) - t.Run("when PluginConfig=nil skips fetching link and native prices", func(t *testing.T) { + t.Run("when PluginConfig is empty", func(t *testing.T) { t.Cleanup(func() { ds.jb = jb }) @@ -372,7 +372,7 @@ func Test_Datasource(t *testing.T) { fetcher.linkPriceErr = errors.New("some error fetching link price") fetcher.nativePriceErr = errors.New("some error fetching native price") - ds.jb.OCR2OracleSpec.PluginConfig = nil + ds.jb.OCR2OracleSpec.PluginConfig = job.JSONConfig{} obs, err := ds.Observe(ctx, repts, false) assert.NoError(t, err) diff --git a/core/services/relay/evm/mercury/v4/data_source.go b/core/services/relay/evm/mercury/v4/data_source.go index 05ec44dc78c..bf45ccc87fd 100644 --- a/core/services/relay/evm/mercury/v4/data_source.go +++ b/core/services/relay/evm/mercury/v4/data_source.go @@ -108,7 +108,9 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam }() var isLink, isNative bool - if ds.feedID == ds.linkFeedID { + if len(ds.jb.OCR2OracleSpec.PluginConfig) == 0 { + obs.LinkPrice.Val = v4.MissingPrice + } else if ds.feedID == ds.linkFeedID { isLink = true } else { wg.Add(1) @@ -126,7 +128,9 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam }() } - if ds.feedID == ds.nativeFeedID { + if len(ds.jb.OCR2OracleSpec.PluginConfig) == 0 { + obs.NativePrice.Val = v4.MissingPrice + } else if ds.feedID == ds.nativeFeedID { isNative = true } else { wg.Add(1) diff --git a/core/services/relay/evm/mercury/v4/data_source_test.go b/core/services/relay/evm/mercury/v4/data_source_test.go index 7b50a922c8d..48aec5989a6 100644 --- a/core/services/relay/evm/mercury/v4/data_source_test.go +++ b/core/services/relay/evm/mercury/v4/data_source_test.go @@ -13,6 +13,7 @@ import ( 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/job" "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" @@ -70,7 +71,16 @@ func (ms *mockSaver) Save(r *pipeline.Run) { func Test_Datasource(t *testing.T) { orm := &mockORM{} - ds := &datasource{orm: orm, lggr: logger.TestLogger(t)} + jb := job.Job{ + Type: job.Type(pipeline.OffchainReporting2JobType), + OCR2OracleSpec: &job.OCR2OracleSpec{ + CaptureEATelemetry: true, + PluginConfig: map[string]interface{}{ + "serverURL": "a", + }, + }, + } + ds := &datasource{orm: orm, lggr: logger.TestLogger(t), jb: jb} ctx := testutils.Context(t) repts := ocrtypes.ReportTimestamp{} @@ -286,6 +296,25 @@ func Test_Datasource(t *testing.T) { assert.EqualError(t, obs.NativePrice.Err, "some error fetching native price") }) + t.Run("when PluginConfig is empty", func(t *testing.T) { + t.Cleanup(func() { + ds.jb = jb + }) + + fetcher.linkPriceErr = errors.New("some error fetching link price") + fetcher.nativePriceErr = errors.New("some error fetching native price") + + ds.jb.OCR2OracleSpec.PluginConfig = job.JSONConfig{} + + obs, err := ds.Observe(ctx, repts, false) + assert.NoError(t, err) + assert.Nil(t, obs.LinkPrice.Err) + assert.Equal(t, obs.LinkPrice.Val, relaymercuryv4.MissingPrice) + assert.Nil(t, obs.NativePrice.Err) + assert.Equal(t, obs.NativePrice.Val, relaymercuryv4.MissingPrice) + assert.Equal(t, big.NewInt(122), obs.BenchmarkPrice.Val) + }) + 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)