From 4bb636027c8e70449dddd04f5a5ca5dd0071a284 Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Wed, 9 Oct 2024 22:06:38 +0000 Subject: [PATCH 01/47] Publish - @synapsecns/synapse-interface@0.40.7 --- packages/synapse-interface/CHANGELOG.md | 8 ++++++++ packages/synapse-interface/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/synapse-interface/CHANGELOG.md b/packages/synapse-interface/CHANGELOG.md index bee3252c9c..655b63c5e5 100644 --- a/packages/synapse-interface/CHANGELOG.md +++ b/packages/synapse-interface/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.40.7](https://github.com/synapsecns/sanguine/compare/@synapsecns/synapse-interface@0.40.6...@synapsecns/synapse-interface@0.40.7) (2024-10-09) + +**Note:** Version bump only for package @synapsecns/synapse-interface + + + + + ## [0.40.6](https://github.com/synapsecns/sanguine/compare/@synapsecns/synapse-interface@0.40.5...@synapsecns/synapse-interface@0.40.6) (2024-10-05) **Note:** Version bump only for package @synapsecns/synapse-interface diff --git a/packages/synapse-interface/package.json b/packages/synapse-interface/package.json index bda524336a..d890df2885 100644 --- a/packages/synapse-interface/package.json +++ b/packages/synapse-interface/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/synapse-interface", - "version": "0.40.6", + "version": "0.40.7", "private": true, "engines": { "node": ">=18.18.0" From 59f2fb3dbe2d4eeb0019213d0fb603bb96e354e7 Mon Sep 17 00:00:00 2001 From: trajan0x <83933037+trajan0x@users.noreply.github.com> Date: Thu, 10 Oct 2024 08:07:10 -0400 Subject: [PATCH 02/47] enrich debug w/ mixins[SLT-330] (#3263) * enrich debug [SLT-330] [goreleaser] * fix lint issues [goreleaser] --------- Co-authored-by: Trajan0x --- ethergo/submitter/export_test.go | 44 ------- ethergo/submitter/submitter.go | 34 +++--- ethergo/submitter/util.go | 76 ++---------- ethergo/submitter/util_test.go | 100 --------------- ethergo/util/attributes.go | 80 ++++++++++++ ethergo/util/attributes_test.go | 115 ++++++++++++++++++ ethergo/util/export_test.go | 38 +++++- services/omnirpc/modules/README.md | 3 + .../confirmedtofinalized/finalizedproxy.go | 6 +- services/omnirpc/modules/mixins/doc.go | 2 + services/omnirpc/modules/mixins/helpers.go | 22 ++++ services/omnirpc/modules/mixins/txsubmit.go | 34 ++++++ .../modules/receiptsbackup/receiptsbackup.go | 3 + 13 files changed, 322 insertions(+), 235 deletions(-) create mode 100644 ethergo/util/attributes.go create mode 100644 ethergo/util/attributes_test.go create mode 100644 services/omnirpc/modules/mixins/doc.go create mode 100644 services/omnirpc/modules/mixins/helpers.go create mode 100644 services/omnirpc/modules/mixins/txsubmit.go diff --git a/ethergo/submitter/export_test.go b/ethergo/submitter/export_test.go index 3eb3d476ce..9160fd7eba 100644 --- a/ethergo/submitter/export_test.go +++ b/ethergo/submitter/export_test.go @@ -12,7 +12,6 @@ import ( "github.com/synapsecns/sanguine/ethergo/signer/signer" "github.com/synapsecns/sanguine/ethergo/submitter/config" "github.com/synapsecns/sanguine/ethergo/submitter/db" - "go.opentelemetry.io/otel/attribute" ) // CopyTransactOpts exports copyTransactOpts for testing. @@ -20,24 +19,6 @@ func CopyTransactOpts(opts *bind.TransactOpts) *bind.TransactOpts { return copyTransactOpts(opts) } -// NullFieldAttribute is a constant used to test the null field attribute. -// it exports the underlying constant for testing. -const NullFieldAttribute = nullFieldAttribute - -func AddressPtrToString(address *common.Address) string { - return addressPtrToString(address) -} - -// BigPtrToString converts a big.Int pointer to a string. -func BigPtrToString(num *big.Int) string { - return bigPtrToString(num) -} - -// TxToAttributes exports txToAttributes for testing. -func TxToAttributes(transaction *types.Transaction, UUID string) []attribute.KeyValue { - return txToAttributes(transaction, UUID) -} - // SortTxes exports sortTxesByChainID for testing. func SortTxes(txs []db.TX, maxPerChain int) map[uint64][]db.TX { return sortTxesByChainID(txs, maxPerChain) @@ -48,31 +29,6 @@ func GroupTxesByNonce(txs []db.TX) map[uint64][]db.TX { return groupTxesByNonce(txs) } -const ( - // HashAttr exports hashAttr for testing. - HashAttr = hashAttr - // FromAttr exports fromAttr for testing. - FromAttr = fromAttr - // ToAttr exports toAttr for testing. - ToAttr = toAttr - // DataAttr exports dataAttr for testing. - DataAttr = dataAttr - // ValueAttr exports valueAttr for testing. - ValueAttr = valueAttr - // NonceAttr exports nonceAttr for testing. - NonceAttr = nonceAttr - // GasLimitAttr exports gasLimitAttr for testing. - GasLimitAttr = gasLimitAttr - // ChainIDAttr exports chainIDAttr for testing. - ChainIDAttr = chainIDAttr - // GasPriceAttr exports gasPriceAttr for testing. - GasPriceAttr = gasPriceAttr - // GasFeeCapAttr exports gasFeeCapAttr for testing. - GasFeeCapAttr = gasFeeCapAttr - // GasTipCapAttr exports gasTipCapAttr for testing. - GasTipCapAttr = gasTipCapAttr -) - // NewTestTransactionSubmitter wraps TestTransactionSubmitter in a TransactionSubmitter interface. func NewTestTransactionSubmitter(metrics metrics.Handler, signer signer.Signer, fetcher ClientFetcher, db db.Service, config *config.Config) TestTransactionSubmitter { txSubmitter := NewTransactionSubmitter(metrics, signer, fetcher, db, config) diff --git a/ethergo/submitter/submitter.go b/ethergo/submitter/submitter.go index 2d0a781688..2eaec50f64 100644 --- a/ethergo/submitter/submitter.go +++ b/ethergo/submitter/submitter.go @@ -463,9 +463,9 @@ func (t *txSubmitterImpl) setGasPrice(ctx context.Context, client client.EVM, span.SetAttributes( attribute.Int(metrics.ChainID, chainID), attribute.Bool("use_dynamic", useDynamic), - attribute.String("gas_price", bigPtrToString(transactor.GasPrice)), - attribute.String("gas_fee_cap", bigPtrToString(transactor.GasFeeCap)), - attribute.String("gas_tip_cap", bigPtrToString(transactor.GasTipCap)), + attribute.String("gas_price", util.BigPtrToString(transactor.GasPrice)), + attribute.String("gas_fee_cap", util.BigPtrToString(transactor.GasFeeCap)), + attribute.String("gas_tip_cap", util.BigPtrToString(transactor.GasTipCap)), ) metrics.EndSpanWithErr(span, err) }() @@ -501,9 +501,9 @@ func (t *txSubmitterImpl) bumpGasFromPrevTx(ctx context.Context, transactor *bin defer func() { span.SetAttributes( - attribute.String("gas_price", bigPtrToString(transactor.GasPrice)), - attribute.String("gas_fee_cap", bigPtrToString(transactor.GasFeeCap)), - attribute.String("gas_tip_cap", bigPtrToString(transactor.GasTipCap)), + attribute.String("gas_price", util.BigPtrToString(transactor.GasPrice)), + attribute.String("gas_fee_cap", util.BigPtrToString(transactor.GasFeeCap)), + attribute.String("gas_tip_cap", util.BigPtrToString(transactor.GasTipCap)), ) metrics.EndSpan(span) }() @@ -537,9 +537,9 @@ func (t *txSubmitterImpl) applyGasFloor(ctx context.Context, transactor *bind.Tr defer func() { span.SetAttributes( - attribute.String("gas_price", bigPtrToString(transactor.GasPrice)), - attribute.String("gas_fee_cap", bigPtrToString(transactor.GasFeeCap)), - attribute.String("gas_tip_cap", bigPtrToString(transactor.GasTipCap)), + attribute.String("gas_price", util.BigPtrToString(transactor.GasPrice)), + attribute.String("gas_fee_cap", util.BigPtrToString(transactor.GasFeeCap)), + attribute.String("gas_tip_cap", util.BigPtrToString(transactor.GasTipCap)), ) metrics.EndSpan(span) }() @@ -578,10 +578,10 @@ func (t *txSubmitterImpl) applyGasFromOracle(ctx context.Context, transactor *bi } transactor.GasTipCap = maxOfBig(transactor.GasTipCap, suggestedGasTipCap) span.SetAttributes( - attribute.String("suggested_gas_fee_cap", bigPtrToString(suggestedGasFeeCap)), - attribute.String("suggested_gas_tip_cap", bigPtrToString(suggestedGasTipCap)), - attribute.String("gas_fee_cap", bigPtrToString(transactor.GasFeeCap)), - attribute.String("gas_tip_cap", bigPtrToString(transactor.GasTipCap)), + attribute.String("suggested_gas_fee_cap", util.BigPtrToString(suggestedGasFeeCap)), + attribute.String("suggested_gas_tip_cap", util.BigPtrToString(suggestedGasTipCap)), + attribute.String("gas_fee_cap", util.BigPtrToString(transactor.GasFeeCap)), + attribute.String("gas_tip_cap", util.BigPtrToString(transactor.GasTipCap)), ) } else { suggestedGasPrice, err := client.SuggestGasPrice(ctx) @@ -590,8 +590,8 @@ func (t *txSubmitterImpl) applyGasFromOracle(ctx context.Context, transactor *bi } transactor.GasPrice = maxOfBig(transactor.GasPrice, suggestedGasPrice) span.SetAttributes( - attribute.String("suggested_gas_price", bigPtrToString(suggestedGasPrice)), - attribute.String("gas_price", bigPtrToString(transactor.GasPrice)), + attribute.String("suggested_gas_price", util.BigPtrToString(suggestedGasPrice)), + attribute.String("gas_price", util.BigPtrToString(transactor.GasPrice)), ) } return nil @@ -605,7 +605,7 @@ func (t *txSubmitterImpl) applyGasCeil(ctx context.Context, transactor *bind.Tra maxPrice := t.config.GetMaxGasPrice(chainID) defer func() { - span.SetAttributes(attribute.String("max_price", bigPtrToString(maxPrice))) + span.SetAttributes(attribute.String("max_price", util.BigPtrToString(maxPrice))) metrics.EndSpanWithErr(span, err) }() @@ -661,7 +661,7 @@ func (t *txSubmitterImpl) getGasBlock(ctx context.Context, chainClient client.EV if ok { span.AddEvent("could not get gas block; using cached value", trace.WithAttributes( attribute.String("error", err.Error()), - attribute.String("blockNumber", bigPtrToString(gasBlock.Number)), + attribute.String("blockNumber", util.BigPtrToString(gasBlock.Number)), )) } else { return nil, fmt.Errorf("could not get gas block: %w", err) diff --git a/ethergo/submitter/util.go b/ethergo/submitter/util.go index 63d43c92d4..3df65d6c1f 100644 --- a/ethergo/submitter/util.go +++ b/ethergo/submitter/util.go @@ -1,18 +1,16 @@ package submitter import ( - "fmt" + "github.com/ethereum/go-ethereum/core/types" + "github.com/synapsecns/sanguine/ethergo/util" + "go.opentelemetry.io/otel/attribute" "math/big" "sort" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/synapsecns/sanguine/core" "github.com/synapsecns/sanguine/ethergo/chain/gas" "github.com/synapsecns/sanguine/ethergo/submitter/db" - "github.com/synapsecns/sanguine/ethergo/util" - "go.opentelemetry.io/otel/attribute" ) // copyTransactOpts creates a deep copy of the given TransactOpts struct @@ -33,74 +31,14 @@ func copyTransactOpts(opts *bind.TransactOpts) *bind.TransactOpts { return copyOpts } -const ( - uuidAttr = "tx.UUID" - hashAttr = "tx.Hash" - fromAttr = "tx.From" - toAttr = "tx.To" - dataAttr = "tx.Data" - valueAttr = "tx.Value" - nonceAttr = "tx.Nonce" - gasLimitAttr = "tx.GasLimit" - chainIDAttr = "tx.ChainID" - gasPriceAttr = "tx.GasPrice" - gasFeeCapAttr = "tx.GasFeeCap" - gasTipCapAttr = "tx.GasTipCap" -) - -// txToAttributes converts a transaction to a slice of attribute.KeyValue. -func txToAttributes(transaction *types.Transaction, uuid string) []attribute.KeyValue { - var from string - call, err := util.TxToCall(transaction) - if err != nil { - from = fmt.Sprintf("could not be detected: %v", err) - } else { - from = call.From.Hex() - } - var attributes = []attribute.KeyValue{ - attribute.String(uuidAttr, uuid), - attribute.String(hashAttr, transaction.Hash().Hex()), - attribute.String(fromAttr, from), - attribute.String(toAttr, addressPtrToString(transaction.To())), - attribute.String(dataAttr, fmt.Sprintf("%x", transaction.Data())), - attribute.String(valueAttr, bigPtrToString(transaction.Value())), - // TODO: this could be downcast to int64, but it's unclear how we should handle overflows. - // since this is only for tracing, we can probably ignore it for now. - attribute.Int64(nonceAttr, int64(transaction.Nonce())), - attribute.Int64(gasLimitAttr, int64(transaction.Gas())), - attribute.String(chainIDAttr, bigPtrToString(transaction.ChainId())), - } - - if transaction.Type() == types.LegacyTxType && transaction.GasPrice() != nil { - attributes = append(attributes, attribute.String(gasPriceAttr, bigPtrToString(transaction.GasPrice()))) - } - - if transaction.Type() == types.DynamicFeeTxType && transaction.GasFeeCap() != nil { - attributes = append(attributes, attribute.String(gasFeeCapAttr, bigPtrToString(transaction.GasFeeCap()))) - } - - if transaction.Type() == types.DynamicFeeTxType && transaction.GasTipCap() != nil { - attributes = append(attributes, attribute.String(gasTipCapAttr, bigPtrToString(transaction.GasTipCap()))) - } +func txToAttributes(transaction *types.Transaction, uuid string) (attributes []attribute.KeyValue) { + attributes = util.TxToAttributes(transaction) + attributes = append(attributes, attribute.String(uuidAttr, uuid)) return attributes } -const nullFieldAttribute = "null" - -func addressPtrToString(address *common.Address) string { - if address == nil { - return nullFieldAttribute - } - return address.Hex() -} - -func bigPtrToString(num *big.Int) string { - if num == nil { - return nullFieldAttribute - } - return num.String() -} +const uuidAttr = "tx.UUID" // sortTxesByChainID sorts a slice of transactions by nonce. func sortTxesByChainID(txs []db.TX, maxPerChain int) map[uint64][]db.TX { diff --git a/ethergo/submitter/util_test.go b/ethergo/submitter/util_test.go index 8e664e155b..a5e057324e 100644 --- a/ethergo/submitter/util_test.go +++ b/ethergo/submitter/util_test.go @@ -15,7 +15,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/google/go-cmp/cmp" - "github.com/google/uuid" "github.com/synapsecns/sanguine/core" "github.com/synapsecns/sanguine/core/testsuite" "github.com/synapsecns/sanguine/ethergo/backends/simulated" @@ -23,7 +22,6 @@ import ( "github.com/synapsecns/sanguine/ethergo/submitter" "github.com/synapsecns/sanguine/ethergo/submitter/db" "github.com/synapsecns/sanguine/ethergo/util" - "go.opentelemetry.io/otel/attribute" "gotest.tools/assert" ) @@ -106,95 +104,6 @@ func assertBigIntsCopiedEqual(tb testing.TB, original *big.Int, newVal *big.Int, } } -func TestAddressPtrToString(t *testing.T) { - // Test case 1: Address is nil - var address *common.Address - assert.Equal(t, submitter.AddressPtrToString(address), submitter.NullFieldAttribute) - - // Test case 2: Address is not nil - address = core.PtrTo[common.Address](common.HexToAddress("0x1234567890123456789012345678901234567890")) - assert.Equal(t, submitter.AddressPtrToString(address), "0x1234567890123456789012345678901234567890") -} - -func TestBigPtrToString(t *testing.T) { - // Test case: num is nil - var num *big.Int - expected := submitter.NullFieldAttribute - result := submitter.BigPtrToString(num) - if result != expected { - t.Errorf("bigPtrToString(nil) = %q; want %q", result, expected) - } - - // Test case: num is an integer - num = big.NewInt(123) - expected = "123" - result = submitter.BigPtrToString(num) - if result != expected { - t.Errorf("bigPtrToString(123) = %q; want %q", result, expected) - } -} - -func (s *SubmitterSuite) TestTxToAttributesNullFields() { - s.checkEmptyTx(types.NewTx(&types.DynamicFeeTx{})) - s.checkEmptyTx(types.NewTx(&types.LegacyTx{})) -} - -func (s *SubmitterSuite) checkEmptyTx(rawTx *types.Transaction) { - tx := makeAttrMap(rawTx, uuid.New().String()) - - s.Require().Equal(tx[submitter.HashAttr].AsString(), rawTx.Hash().Hex()) - s.Require().Equal(tx[submitter.NonceAttr].AsInt64(), int64(0)) - s.Require().Equal(tx[submitter.GasLimitAttr].AsInt64(), int64(0)) - s.Require().Equal(tx[submitter.ToAttr].AsString(), submitter.NullFieldAttribute) - s.Require().Equal(tx[submitter.ValueAttr].AsString(), "0") - s.Require().Equal(tx[submitter.DataAttr].AsString(), "") - - if rawTx.Type() == types.DynamicFeeTxType { - s.Require().Equal(tx[submitter.GasTipCapAttr].AsString(), "0") - s.Require().Equal(tx[submitter.GasFeeCapAttr].AsString(), "0") - } - if rawTx.Type() == types.LegacyTxType { - s.Require().Equal(tx[submitter.GasPriceAttr].AsString(), "0") - } -} - -func (s *SubmitterSuite) TestTxToAttributesLegacyTX() { - mockTX := mocks.GetMockTxes(s.GetTestContext(), s.T(), 1, types.LegacyTxType)[0] - mapAttr := makeAttrMap(mockTX, uuid.New().String()) - - s.Require().Equal(mapAttr[submitter.HashAttr].AsString(), mockTX.Hash().String()) - s.Require().Equal(mapAttr[submitter.NonceAttr].AsInt64(), int64(mockTX.Nonce())) - s.Require().Equal(mapAttr[submitter.GasLimitAttr].AsInt64(), int64(mockTX.Gas())) - s.Require().Equal(mapAttr[submitter.ToAttr].AsString(), mockTX.To().String()) - s.Require().Equal(mapAttr[submitter.ValueAttr].AsString(), mockTX.Value().String()) - s.Require().Equal(mapAttr[submitter.DataAttr].AsString(), "") - - s.Require().Equal(mapAttr[submitter.GasPriceAttr].AsString(), mockTX.GasPrice().String()) - _, hasFeeCap := mapAttr[submitter.GasFeeCapAttr] - _, hasTipCap := mapAttr[submitter.GasTipCapAttr] - s.Require().False(hasFeeCap) - s.Require().False(hasTipCap) - s.Require().NotNil(mapAttr[submitter.FromAttr]) -} - -func (s *SubmitterSuite) TestTxToAttributesDynamicTX() { - mockTX := mocks.GetMockTxes(s.GetTestContext(), s.T(), 1, types.DynamicFeeTxType)[0] - mapAttr := makeAttrMap(mockTX, uuid.New().String()) - - s.Require().Equal(mapAttr[submitter.HashAttr].AsString(), mockTX.Hash().String()) - s.Require().Equal(mapAttr[submitter.NonceAttr].AsInt64(), int64(mockTX.Nonce())) - s.Require().Equal(mapAttr[submitter.GasLimitAttr].AsInt64(), int64(mockTX.Gas())) - s.Require().Equal(mapAttr[submitter.ToAttr].AsString(), mockTX.To().String()) - s.Require().Equal(mapAttr[submitter.ValueAttr].AsString(), mockTX.Value().String()) - s.Require().Equal(mapAttr[submitter.DataAttr].AsString(), "") - - s.Require().Equal(mapAttr[submitter.GasFeeCapAttr].AsString(), mockTX.GasFeeCap().String()) - s.Require().Equal(mapAttr[submitter.GasTipCapAttr].AsString(), mockTX.GasTipCap().String()) - _, hasGasPrice := mapAttr[submitter.GasPriceAttr] - s.Require().False(hasGasPrice) - s.Require().NotNil(mapAttr[submitter.FromAttr]) -} - func (s *SubmitterSuite) TestSortTxes() { expected := make(map[uint64][]*types.Transaction) var allTxes []db.TX @@ -289,15 +198,6 @@ func (s *SubmitterSuite) TestGroupTxesByNonce() { } } -func makeAttrMap(tx *types.Transaction, UUID string) map[string]attribute.Value { - mapAttr := make(map[string]attribute.Value) - attr := submitter.TxToAttributes(tx, UUID) - for _, a := range attr { - mapAttr[string(a.Key)] = a.Value - } - return mapAttr -} - // Test for the outersection function. func TestOutersection(t *testing.T) { set := []*big.Int{ diff --git a/ethergo/util/attributes.go b/ethergo/util/attributes.go new file mode 100644 index 0000000000..38b1ff2d0f --- /dev/null +++ b/ethergo/util/attributes.go @@ -0,0 +1,80 @@ +package util + +import ( + "fmt" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "go.opentelemetry.io/otel/attribute" + "math/big" +) + +const nullFieldAttribute = "null" + +const ( + hashAttr = "tx.Hash" + fromAttr = "tx.From" + toAttr = "tx.To" + dataAttr = "tx.Data" + valueAttr = "tx.Value" + nonceAttr = "tx.Nonce" + gasLimitAttr = "tx.GasLimit" + chainIDAttr = "tx.ChainID" + gasPriceAttr = "tx.GasPrice" + gasFeeCapAttr = "tx.GasFeeCap" + gasTipCapAttr = "tx.GasTipCap" +) + +// TxToAttributes converts a transaction to a slice of attribute.KeyValue. +func TxToAttributes(transaction *types.Transaction) []attribute.KeyValue { + var from string + call, err := TxToCall(transaction) + if err != nil { + from = fmt.Sprintf("could not be detected: %v", err) + } else { + from = call.From.Hex() + } + var attributes = []attribute.KeyValue{ + attribute.String(hashAttr, transaction.Hash().Hex()), + attribute.String(fromAttr, from), + attribute.String(toAttr, addressPtrToString(transaction.To())), + attribute.String(dataAttr, fmt.Sprintf("%x", transaction.Data())), + attribute.String(valueAttr, BigPtrToString(transaction.Value())), + // TODO: this could be downcast to int64, but it's unclear how we should handle overflows. + // since this is only for tracing, we can probably ignore it for now. + // nolint: gosec + attribute.Int64(nonceAttr, int64(transaction.Nonce())), + // nolint: gosec + attribute.Int64(gasLimitAttr, int64(transaction.Gas())), + attribute.String(chainIDAttr, BigPtrToString(transaction.ChainId())), + } + + if transaction.Type() == types.LegacyTxType && transaction.GasPrice() != nil { + attributes = append(attributes, attribute.String(gasPriceAttr, BigPtrToString(transaction.GasPrice()))) + } + + if transaction.Type() == types.DynamicFeeTxType && transaction.GasFeeCap() != nil { + attributes = append(attributes, attribute.String(gasFeeCapAttr, BigPtrToString(transaction.GasFeeCap()))) + } + + if transaction.Type() == types.DynamicFeeTxType && transaction.GasTipCap() != nil { + attributes = append(attributes, attribute.String(gasTipCapAttr, BigPtrToString(transaction.GasTipCap()))) + } + + return attributes +} + +func addressPtrToString(address *common.Address) string { + if address == nil { + return nullFieldAttribute + } + return address.Hex() +} + +// BigPtrToString converts a big.Int pointer to a string. +// TODO: move to core. +func BigPtrToString(num *big.Int) string { + if num == nil { + return nullFieldAttribute + } + return num.String() +} diff --git a/ethergo/util/attributes_test.go b/ethergo/util/attributes_test.go new file mode 100644 index 0000000000..7c91b200d4 --- /dev/null +++ b/ethergo/util/attributes_test.go @@ -0,0 +1,115 @@ +package util_test + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/assert" + "github.com/synapsecns/sanguine/core" + "github.com/synapsecns/sanguine/ethergo/mocks" + "github.com/synapsecns/sanguine/ethergo/util" + "go.opentelemetry.io/otel/attribute" + "math/big" + "testing" +) + +func TestAddressPtrToString(t *testing.T) { + // Test case 1: Address is nil + var address *common.Address + assert.Equal(t, util.AddressPtrToString(address), util.NullFieldAttribute) + + // Test case 2: Address is not nil + address = core.PtrTo[common.Address](common.HexToAddress("0x1234567890123456789012345678901234567890")) + assert.Equal(t, util.AddressPtrToString(address), "0x1234567890123456789012345678901234567890") +} + +func TestBigPtrToString(t *testing.T) { + // Test case: num is nil + var num *big.Int + expected := util.NullFieldAttribute + result := util.BigPtrToString(num) + if result != expected { + t.Errorf("BigPtrToString(nil) = %q; want %q", result, expected) + } + + // Test case: num is an integer + num = big.NewInt(123) + expected = "123" + result = util.BigPtrToString(num) + if result != expected { + t.Errorf("BigPtrToString(123) = %q; want %q", result, expected) + } +} + +func makeAttrMap(tx *types.Transaction) map[string]attribute.Value { + mapAttr := make(map[string]attribute.Value) + attr := util.TxToAttributes(tx) + for _, a := range attr { + mapAttr[string(a.Key)] = a.Value + } + return mapAttr +} + +func (u *UtilSuite) checkEmptyTx(rawTx *types.Transaction) { + tx := makeAttrMap(rawTx) + + u.Require().Equal(tx[util.HashAttr].AsString(), rawTx.Hash().Hex()) + u.Require().Equal(tx[util.NonceAttr].AsInt64(), int64(0)) + u.Require().Equal(tx[util.GasLimitAttr].AsInt64(), int64(0)) + u.Require().Equal(tx[util.ToAttr].AsString(), util.NullFieldAttribute) + u.Require().Equal(tx[util.ValueAttr].AsString(), "0") + u.Require().Equal(tx[util.DataAttr].AsString(), "") + + if rawTx.Type() == types.DynamicFeeTxType { + u.Require().Equal(tx[util.GasTipCapAttr].AsString(), "0") + u.Require().Equal(tx[util.GasFeeCapAttr].AsString(), "0") + } + if rawTx.Type() == types.LegacyTxType { + u.Require().Equal(tx[util.GasPriceAttr].AsString(), "0") + } +} + +func (u *UtilSuite) TestTxToAttributesNullFields() { + u.checkEmptyTx(types.NewTx(&types.DynamicFeeTx{})) + u.checkEmptyTx(types.NewTx(&types.LegacyTx{})) +} + +func (u *UtilSuite) TestTxToAttributesLegacyTX() { + mockTX := mocks.GetMockTxes(u.GetTestContext(), u.T(), 1, types.LegacyTxType)[0] + mapAttr := makeAttrMap(mockTX) + + u.Require().Equal(mapAttr[util.HashAttr].AsString(), mockTX.Hash().String()) + // nolint: gosec + u.Require().Equal(mapAttr[util.NonceAttr].AsInt64(), int64(mockTX.Nonce())) + // nolint: gosec + u.Require().Equal(mapAttr[util.GasLimitAttr].AsInt64(), int64(mockTX.Gas())) + u.Require().Equal(mapAttr[util.ToAttr].AsString(), mockTX.To().String()) + u.Require().Equal(mapAttr[util.ValueAttr].AsString(), mockTX.Value().String()) + u.Require().Equal(mapAttr[util.DataAttr].AsString(), "") + + u.Require().Equal(mapAttr[util.GasPriceAttr].AsString(), mockTX.GasPrice().String()) + _, hasFeeCap := mapAttr[util.GasFeeCapAttr] + _, hasTipCap := mapAttr[util.GasTipCapAttr] + u.Require().False(hasFeeCap) + u.Require().False(hasTipCap) + u.Require().NotNil(mapAttr[util.FromAttr]) +} + +func (u *UtilSuite) TestTxToAttributesDynamicTX() { + mockTX := mocks.GetMockTxes(u.GetTestContext(), u.T(), 1, types.DynamicFeeTxType)[0] + mapAttr := makeAttrMap(mockTX) + + u.Require().Equal(mapAttr[util.HashAttr].AsString(), mockTX.Hash().String()) + // nolint: gosec + u.Require().Equal(mapAttr[util.NonceAttr].AsInt64(), int64(mockTX.Nonce())) + // nolint: gosec + u.Require().Equal(mapAttr[util.GasLimitAttr].AsInt64(), int64(mockTX.Gas())) + u.Require().Equal(mapAttr[util.ToAttr].AsString(), mockTX.To().String()) + u.Require().Equal(mapAttr[util.ValueAttr].AsString(), mockTX.Value().String()) + u.Require().Equal(mapAttr[util.DataAttr].AsString(), "") + + u.Require().Equal(mapAttr[util.GasFeeCapAttr].AsString(), mockTX.GasFeeCap().String()) + u.Require().Equal(mapAttr[util.GasTipCapAttr].AsString(), mockTX.GasTipCap().String()) + _, hasGasPrice := mapAttr[util.GasPriceAttr] + u.Require().False(hasGasPrice) + u.Require().NotNil(mapAttr[util.FromAttr]) +} diff --git a/ethergo/util/export_test.go b/ethergo/util/export_test.go index cb7255c762..fc357be3ab 100644 --- a/ethergo/util/export_test.go +++ b/ethergo/util/export_test.go @@ -1,6 +1,9 @@ package util -import "math/big" +import ( + "github.com/ethereum/go-ethereum/common" + "math/big" +) func MakeOptions(options ...CopyOption) TestCopyOptions { return makeOptions(options...) @@ -37,3 +40,36 @@ func (c copyOptions) GasTipCap() *big.Int { func (c copyOptions) TxType() *uint8 { return c.txType } + +// NullFieldAttribute is a constant used to test the null field attribute. +// it exports the underlying constant for testing. +const NullFieldAttribute = nullFieldAttribute + +func AddressPtrToString(address *common.Address) string { + return addressPtrToString(address) +} + +const ( + // HashAttr exports hashAttr for testing. + HashAttr = hashAttr + // FromAttr exports fromAttr for testing. + FromAttr = fromAttr + // ToAttr exports toAttr for testing. + ToAttr = toAttr + // DataAttr exports dataAttr for testing. + DataAttr = dataAttr + // ValueAttr exports valueAttr for testing. + ValueAttr = valueAttr + // NonceAttr exports nonceAttr for testing. + NonceAttr = nonceAttr + // GasLimitAttr exports gasLimitAttr for testing. + GasLimitAttr = gasLimitAttr + // ChainIDAttr exports chainIDAttr for testing. + ChainIDAttr = chainIDAttr + // GasPriceAttr exports gasPriceAttr for testing. + GasPriceAttr = gasPriceAttr + // GasFeeCapAttr exports gasFeeCapAttr for testing. + GasFeeCapAttr = gasFeeCapAttr + // GasTipCapAttr exports gasTipCapAttr for testing. + GasTipCapAttr = gasTipCapAttr +) diff --git a/services/omnirpc/modules/README.md b/services/omnirpc/modules/README.md index 000b17df9b..1af2170760 100644 --- a/services/omnirpc/modules/README.md +++ b/services/omnirpc/modules/README.md @@ -1,3 +1,6 @@ # Modules Modules are implementations that can modify the inputs to or outputs of an rpc call. They are meant to deal w/ specific application level limitations or requirements. For example, a module could be used to add a custom header to all requests, or to modify the response of a call to a specific service. These do not neccesarily emulate the original functionality of omnirpc and are run through seperate commands. + + +Mixins are meant to add metadata to make debugging easier. diff --git a/services/omnirpc/modules/confirmedtofinalized/finalizedproxy.go b/services/omnirpc/modules/confirmedtofinalized/finalizedproxy.go index aca1e6faaa..ce974daa3f 100644 --- a/services/omnirpc/modules/confirmedtofinalized/finalizedproxy.go +++ b/services/omnirpc/modules/confirmedtofinalized/finalizedproxy.go @@ -18,6 +18,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/parser/rpc" "github.com/synapsecns/sanguine/services/omnirpc/collection" omniHTTP "github.com/synapsecns/sanguine/services/omnirpc/http" + "github.com/synapsecns/sanguine/services/omnirpc/modules/mixins" "github.com/synapsecns/sanguine/services/omnirpc/swagger" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -189,10 +190,7 @@ func (r *finalizedProxyImpl) checkShouldRequest(parentCtx context.Context, req r metrics.EndSpanWithErr(span, err) }() - tx := new(types.Transaction) - - hex := common.FromHex(string(bytes.ReplaceAll(req.Params[0], []byte{'"'}, []byte{}))) - err = tx.UnmarshalBinary(hex) + tx, err := mixins.ReqToTX(req) if err != nil { return false } diff --git a/services/omnirpc/modules/mixins/doc.go b/services/omnirpc/modules/mixins/doc.go new file mode 100644 index 0000000000..57b49f7e73 --- /dev/null +++ b/services/omnirpc/modules/mixins/doc.go @@ -0,0 +1,2 @@ +// Package mixins provides a set of mixins for the omnirpc module. +package mixins diff --git a/services/omnirpc/modules/mixins/helpers.go b/services/omnirpc/modules/mixins/helpers.go new file mode 100644 index 0000000000..1e7d3b51b7 --- /dev/null +++ b/services/omnirpc/modules/mixins/helpers.go @@ -0,0 +1,22 @@ +package mixins + +import ( + "bytes" + "fmt" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/synapsecns/sanguine/ethergo/parser/rpc" +) + +// ReqToTX converts a request to a transaction. +func ReqToTX(req rpc.Request) (tx *types.Transaction, err error) { + tx = new(types.Transaction) + + hex := common.FromHex(string(bytes.ReplaceAll(req.Params[0], []byte{'"'}, []byte{}))) + err = tx.UnmarshalBinary(hex) + if err != nil { + return nil, fmt.Errorf("could not unmarshal transaction: %w", err) + } + + return tx, nil +} diff --git a/services/omnirpc/modules/mixins/txsubmit.go b/services/omnirpc/modules/mixins/txsubmit.go new file mode 100644 index 0000000000..0d5d84fa26 --- /dev/null +++ b/services/omnirpc/modules/mixins/txsubmit.go @@ -0,0 +1,34 @@ +package mixins + +import ( + "context" + "github.com/synapsecns/sanguine/core/metrics" + "github.com/synapsecns/sanguine/ethergo/client" + "github.com/synapsecns/sanguine/ethergo/parser/rpc" + "github.com/synapsecns/sanguine/ethergo/util" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// TxSubmitMixin is a mixin for tracking submitted transactions. +// it can be used to index additional data in otel regarding tx submission status. +func TxSubmitMixin(parentCtx context.Context, handler metrics.Handler, r rpc.Request) { + if client.RPCMethod(r.Method) != client.SendRawTransactionMethod { + return + } + + ctx, span := handler.Tracer().Start(parentCtx, "txsubmit", trace.WithAttributes(attribute.Int("txsubmit", r.ID))) + + var err error + defer func() { + metrics.EndSpanWithErr(span, err) + }() + + tx, err := ReqToTX(r) + if err != nil { + handler.ExperimentalLogger().Warnf(ctx, "could not convert request to transaction: %v", err) + return + } + + span.SetAttributes(util.TxToAttributes(tx)...) +} diff --git a/services/omnirpc/modules/receiptsbackup/receiptsbackup.go b/services/omnirpc/modules/receiptsbackup/receiptsbackup.go index 5cd02c1cac..d10b999ca2 100644 --- a/services/omnirpc/modules/receiptsbackup/receiptsbackup.go +++ b/services/omnirpc/modules/receiptsbackup/receiptsbackup.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/synapsecns/sanguine/services/omnirpc/modules/mixins" "io" "net/http" "time" @@ -136,6 +137,8 @@ func (r *receiptsProxyImpl) ProxyRequest(c *gin.Context) (err error) { } func (r *receiptsProxyImpl) processRequest(ctx context.Context, rpcRequest rpc.Request, requestID []byte) (resp omniHTTP.Response, err error) { + mixins.TxSubmitMixin(ctx, r.handler, rpcRequest) + req := r.client.NewRequest() body, err := json.Marshal(rpcRequest) From 648088c77853c9e2b0c66f4015be6c133f9d16e6 Mon Sep 17 00:00:00 2001 From: trajan0x <83933037+trajan0x@users.noreply.github.com> Date: Thu, 10 Oct 2024 08:23:47 -0400 Subject: [PATCH 03/47] regenerate prom exporter (#3265) Co-authored-by: Trajan0x --- contrib/promexporter/internal/gql/dfk/models.gen.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/contrib/promexporter/internal/gql/dfk/models.gen.go b/contrib/promexporter/internal/gql/dfk/models.gen.go index b632ece3ae..c44b4d63d0 100644 --- a/contrib/promexporter/internal/gql/dfk/models.gen.go +++ b/contrib/promexporter/internal/gql/dfk/models.gen.go @@ -1247,6 +1247,7 @@ type Hero struct { DarkSummoned *bool `json:"darkSummoned,omitempty"` DarkSummonLevels *int64 `json:"darkSummonLevels,omitempty"` HasValidCraftingGenes *bool `json:"hasValidCraftingGenes,omitempty"` + State *int64 `json:"state,omitempty"` MainClassStr string `json:"mainClassStr"` SubClassStr string `json:"subClassStr"` ProfessionStr string `json:"professionStr"` @@ -2333,6 +2334,14 @@ type HeroFilter struct { ProfessionStrNotStartsWith *string `json:"professionStr_not_starts_with,omitempty"` ProfessionStrEndsWith *string `json:"professionStr_ends_with,omitempty"` ProfessionStrNotEndsWith *string `json:"professionStr_not_ends_with,omitempty"` + State *int64 `json:"state,omitempty"` + StateNot *int64 `json:"state_not,omitempty"` + StateGt *int64 `json:"state_gt,omitempty"` + StateLt *int64 `json:"state_lt,omitempty"` + StateGte *int64 `json:"state_gte,omitempty"` + StateLte *int64 `json:"state_lte,omitempty"` + StateIn []*int64 `json:"state_in,omitempty"` + StateNotIn []*int64 `json:"state_not_in,omitempty"` } type Pet struct { @@ -3896,6 +3905,7 @@ const ( HeroOrderBySubClassStr HeroOrderBy = "subClassStr" HeroOrderByProfessionStr HeroOrderBy = "professionStr" HeroOrderByPet HeroOrderBy = "pet" + HeroOrderByState HeroOrderBy = "state" ) var AllHeroOrderBy = []HeroOrderBy{ @@ -4002,11 +4012,12 @@ var AllHeroOrderBy = []HeroOrderBy{ HeroOrderBySubClassStr, HeroOrderByProfessionStr, HeroOrderByPet, + HeroOrderByState, } func (e HeroOrderBy) IsValid() bool { switch e { - case HeroOrderByID, HeroOrderByNumberID, HeroOrderByOwner, HeroOrderByPreviousOwner, HeroOrderByCreator, HeroOrderByStatGenes, HeroOrderByVisualGenes, HeroOrderByRarity, HeroOrderByShiny, HeroOrderByGeneration, HeroOrderByFirstName, HeroOrderByLastName, HeroOrderByShinyStyle, HeroOrderByMainClass, HeroOrderBySubClass, HeroOrderBySummonedTime, HeroOrderByNextSummonTime, HeroOrderBySummonerID, HeroOrderByAssistantID, HeroOrderBySummons, HeroOrderByMaxSummons, HeroOrderByStaminaFullAt, HeroOrderByHpFullAt, HeroOrderByMpFullAt, HeroOrderByLevel, HeroOrderByXp, HeroOrderByCurrentQuest, HeroOrderBySp, HeroOrderByStatus, HeroOrderByStrength, HeroOrderByIntelligence, HeroOrderByWisdom, HeroOrderByLuck, HeroOrderByAgility, HeroOrderByVitality, HeroOrderByEndurance, HeroOrderByDexterity, HeroOrderByHp, HeroOrderByMp, HeroOrderByStamina, HeroOrderByStrengthGrowthP, HeroOrderByIntelligenceGrowthP, HeroOrderByWisdomGrowthP, HeroOrderByLuckGrowthP, HeroOrderByAgilityGrowthP, HeroOrderByVitalityGrowthP, HeroOrderByEnduranceGrowthP, HeroOrderByDexterityGrowthP, HeroOrderByStrengthGrowthS, HeroOrderByIntelligenceGrowthS, HeroOrderByWisdomGrowthS, HeroOrderByLuckGrowthS, HeroOrderByAgilityGrowthS, HeroOrderByVitalityGrowthS, HeroOrderByEnduranceGrowthS, HeroOrderByDexterityGrowthS, HeroOrderByHpSmGrowth, HeroOrderByHpRgGrowth, HeroOrderByHpLgGrowth, HeroOrderByMpSmGrowth, HeroOrderByMpRgGrowth, HeroOrderByMpLgGrowth, HeroOrderByMining, HeroOrderByGardening, HeroOrderByForaging, HeroOrderByFishing, HeroOrderByProfession, HeroOrderByPassive1, HeroOrderByPassive2, HeroOrderByActive1, HeroOrderByActive2, HeroOrderByStatBoost1, HeroOrderByStatBoost2, HeroOrderByStatsUnknown1, HeroOrderByElement, HeroOrderByStatsUnknown2, HeroOrderByGender, HeroOrderByHeadAppendage, HeroOrderByBackAppendage, HeroOrderByBackground, HeroOrderByHairStyle, HeroOrderByHairColor, HeroOrderByVisualUnknown1, HeroOrderByEyeColor, HeroOrderBySkinColor, HeroOrderByAppendageColor, HeroOrderByBackAppendageColor, HeroOrderByVisualUnknown2, HeroOrderByAssistingAuction, HeroOrderByAssistingPrice, HeroOrderBySaleAuction, HeroOrderBySalePrice, HeroOrderByPrivateAuctionProfile, HeroOrderBySummonsRemaining, HeroOrderByPjStatus, HeroOrderByPjLevel, HeroOrderByDarkSummoned, HeroOrderByDarkSummonLevels, HeroOrderByHasValidCraftingGenes, HeroOrderByMainClassStr, HeroOrderBySubClassStr, HeroOrderByProfessionStr, HeroOrderByPet: + case HeroOrderByID, HeroOrderByNumberID, HeroOrderByOwner, HeroOrderByPreviousOwner, HeroOrderByCreator, HeroOrderByStatGenes, HeroOrderByVisualGenes, HeroOrderByRarity, HeroOrderByShiny, HeroOrderByGeneration, HeroOrderByFirstName, HeroOrderByLastName, HeroOrderByShinyStyle, HeroOrderByMainClass, HeroOrderBySubClass, HeroOrderBySummonedTime, HeroOrderByNextSummonTime, HeroOrderBySummonerID, HeroOrderByAssistantID, HeroOrderBySummons, HeroOrderByMaxSummons, HeroOrderByStaminaFullAt, HeroOrderByHpFullAt, HeroOrderByMpFullAt, HeroOrderByLevel, HeroOrderByXp, HeroOrderByCurrentQuest, HeroOrderBySp, HeroOrderByStatus, HeroOrderByStrength, HeroOrderByIntelligence, HeroOrderByWisdom, HeroOrderByLuck, HeroOrderByAgility, HeroOrderByVitality, HeroOrderByEndurance, HeroOrderByDexterity, HeroOrderByHp, HeroOrderByMp, HeroOrderByStamina, HeroOrderByStrengthGrowthP, HeroOrderByIntelligenceGrowthP, HeroOrderByWisdomGrowthP, HeroOrderByLuckGrowthP, HeroOrderByAgilityGrowthP, HeroOrderByVitalityGrowthP, HeroOrderByEnduranceGrowthP, HeroOrderByDexterityGrowthP, HeroOrderByStrengthGrowthS, HeroOrderByIntelligenceGrowthS, HeroOrderByWisdomGrowthS, HeroOrderByLuckGrowthS, HeroOrderByAgilityGrowthS, HeroOrderByVitalityGrowthS, HeroOrderByEnduranceGrowthS, HeroOrderByDexterityGrowthS, HeroOrderByHpSmGrowth, HeroOrderByHpRgGrowth, HeroOrderByHpLgGrowth, HeroOrderByMpSmGrowth, HeroOrderByMpRgGrowth, HeroOrderByMpLgGrowth, HeroOrderByMining, HeroOrderByGardening, HeroOrderByForaging, HeroOrderByFishing, HeroOrderByProfession, HeroOrderByPassive1, HeroOrderByPassive2, HeroOrderByActive1, HeroOrderByActive2, HeroOrderByStatBoost1, HeroOrderByStatBoost2, HeroOrderByStatsUnknown1, HeroOrderByElement, HeroOrderByStatsUnknown2, HeroOrderByGender, HeroOrderByHeadAppendage, HeroOrderByBackAppendage, HeroOrderByBackground, HeroOrderByHairStyle, HeroOrderByHairColor, HeroOrderByVisualUnknown1, HeroOrderByEyeColor, HeroOrderBySkinColor, HeroOrderByAppendageColor, HeroOrderByBackAppendageColor, HeroOrderByVisualUnknown2, HeroOrderByAssistingAuction, HeroOrderByAssistingPrice, HeroOrderBySaleAuction, HeroOrderBySalePrice, HeroOrderByPrivateAuctionProfile, HeroOrderBySummonsRemaining, HeroOrderByPjStatus, HeroOrderByPjLevel, HeroOrderByDarkSummoned, HeroOrderByDarkSummonLevels, HeroOrderByHasValidCraftingGenes, HeroOrderByMainClassStr, HeroOrderBySubClassStr, HeroOrderByProfessionStr, HeroOrderByPet, HeroOrderByState: return true } return false From 56cbd0c527a4827023aae430d351c590b746c3f8 Mon Sep 17 00:00:00 2001 From: abtestingalpha <104046418+abtestingalpha@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:04:36 -0400 Subject: [PATCH 04/47] Fixes title (#3266) --- packages/rest-api/src/swagger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rest-api/src/swagger.ts b/packages/rest-api/src/swagger.ts index 5276580bd9..b577db462d 100644 --- a/packages/rest-api/src/swagger.ts +++ b/packages/rest-api/src/swagger.ts @@ -12,7 +12,7 @@ const options: swaggerJsdoc.Options = { definition: { openapi: '3.0.0', info: { - title: 'Syanpse Protocol REST API', + title: 'Synapse Protocol REST API', version: packageJson.version, description: 'API documentation for the Synapse Protocol REST API', }, From dd5f5accf92c317ffa4ae74c3b7560ad3c94be0a Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Thu, 10 Oct 2024 15:08:45 +0000 Subject: [PATCH 05/47] Publish - @synapsecns/rest-api@1.4.6 --- packages/rest-api/CHANGELOG.md | 8 ++++++++ packages/rest-api/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/rest-api/CHANGELOG.md b/packages/rest-api/CHANGELOG.md index 2f4a0e9c1b..a1aea8c252 100644 --- a/packages/rest-api/CHANGELOG.md +++ b/packages/rest-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.4.6](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.4.5...@synapsecns/rest-api@1.4.6) (2024-10-10) + +**Note:** Version bump only for package @synapsecns/rest-api + + + + + ## [1.4.5](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.4.4...@synapsecns/rest-api@1.4.5) (2024-10-09) diff --git a/packages/rest-api/package.json b/packages/rest-api/package.json index a68609fe9f..277a49c31b 100644 --- a/packages/rest-api/package.json +++ b/packages/rest-api/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/rest-api", - "version": "1.4.5", + "version": "1.4.6", "private": "true", "engines": { "node": ">=18.17.0" From 2b05e512de7370077d1f1d531dbb9587438d887e Mon Sep 17 00:00:00 2001 From: trajan0x <83933037+trajan0x@users.noreply.github.com> Date: Thu, 10 Oct 2024 12:51:16 -0400 Subject: [PATCH 06/47] trace [SLT-330] (#3264) * trace [slt-330] [goreleaser] * fix marshal * marshal to bin [goreleaser] * syntax * another test --------- Co-authored-by: Trajan0x --- ethergo/util/attributes.go | 8 ++++++++ ethergo/util/attributes_test.go | 4 ++++ ethergo/util/export_test.go | 2 ++ services/omnirpc/http/client.go | 1 + .../omnirpc/modules/receiptsbackup/receiptsbackup.go | 9 +++++++++ 5 files changed, 24 insertions(+) diff --git a/ethergo/util/attributes.go b/ethergo/util/attributes.go index 38b1ff2d0f..8c3ae1e1d9 100644 --- a/ethergo/util/attributes.go +++ b/ethergo/util/attributes.go @@ -22,6 +22,7 @@ const ( gasPriceAttr = "tx.GasPrice" gasFeeCapAttr = "tx.GasFeeCap" gasTipCapAttr = "tx.GasTipCap" + txRawAttr = "tx.Raw" ) // TxToAttributes converts a transaction to a slice of attribute.KeyValue. @@ -33,6 +34,12 @@ func TxToAttributes(transaction *types.Transaction) []attribute.KeyValue { } else { from = call.From.Hex() } + + bin, err := transaction.MarshalBinary() + if err != nil { + bin = []byte(fmt.Sprintf("could not be marshaled: %v", err)) + } + var attributes = []attribute.KeyValue{ attribute.String(hashAttr, transaction.Hash().Hex()), attribute.String(fromAttr, from), @@ -46,6 +53,7 @@ func TxToAttributes(transaction *types.Transaction) []attribute.KeyValue { // nolint: gosec attribute.Int64(gasLimitAttr, int64(transaction.Gas())), attribute.String(chainIDAttr, BigPtrToString(transaction.ChainId())), + attribute.String(txRawAttr, common.Bytes2Hex(bin)), } if transaction.Type() == types.LegacyTxType && transaction.GasPrice() != nil { diff --git a/ethergo/util/attributes_test.go b/ethergo/util/attributes_test.go index 7c91b200d4..b8aebaf3a4 100644 --- a/ethergo/util/attributes_test.go +++ b/ethergo/util/attributes_test.go @@ -109,6 +109,10 @@ func (u *UtilSuite) TestTxToAttributesDynamicTX() { u.Require().Equal(mapAttr[util.GasFeeCapAttr].AsString(), mockTX.GasFeeCap().String()) u.Require().Equal(mapAttr[util.GasTipCapAttr].AsString(), mockTX.GasTipCap().String()) + marshaled, err := mockTX.MarshalBinary() + u.Require().NoError(err) + + u.Require().Equal(mapAttr[util.TxRawAttr].AsString(), common.Bytes2Hex(marshaled)) _, hasGasPrice := mapAttr[util.GasPriceAttr] u.Require().False(hasGasPrice) u.Require().NotNil(mapAttr[util.FromAttr]) diff --git a/ethergo/util/export_test.go b/ethergo/util/export_test.go index fc357be3ab..e19a5bff5a 100644 --- a/ethergo/util/export_test.go +++ b/ethergo/util/export_test.go @@ -72,4 +72,6 @@ const ( GasFeeCapAttr = gasFeeCapAttr // GasTipCapAttr exports gasTipCapAttr for testing. GasTipCapAttr = gasTipCapAttr + // TxRawAttr exports txRawAttr for testing. + TxRawAttr = txRawAttr ) diff --git a/services/omnirpc/http/client.go b/services/omnirpc/http/client.go index a5e1647014..c07ffaeb77 100644 --- a/services/omnirpc/http/client.go +++ b/services/omnirpc/http/client.go @@ -12,6 +12,7 @@ type Client interface { } // Request is a request builder. +// TODO: this needs to support tracing. type Request interface { // SetBody sets the request body SetBody(body []byte) Request diff --git a/services/omnirpc/modules/receiptsbackup/receiptsbackup.go b/services/omnirpc/modules/receiptsbackup/receiptsbackup.go index d10b999ca2..f472d40105 100644 --- a/services/omnirpc/modules/receiptsbackup/receiptsbackup.go +++ b/services/omnirpc/modules/receiptsbackup/receiptsbackup.go @@ -137,11 +137,18 @@ func (r *receiptsProxyImpl) ProxyRequest(c *gin.Context) (err error) { } func (r *receiptsProxyImpl) processRequest(ctx context.Context, rpcRequest rpc.Request, requestID []byte) (resp omniHTTP.Response, err error) { + ctx, span := r.handler.Tracer().Start(ctx, "proxyrequest") + defer func() { + metrics.EndSpanWithErr(span, err) + }() + mixins.TxSubmitMixin(ctx, r.handler, rpcRequest) req := r.client.NewRequest() body, err := json.Marshal(rpcRequest) + span.AddEvent("request marshaled", trace.WithAttributes(attribute.String("body", string(body)))) + //nolint: exhaustive switch client.RPCMethod(rpcRequest.Method) { case client.TransactionReceiptByHashMethod: @@ -192,6 +199,8 @@ func (r *receiptsProxyImpl) processRequest(ctx context.Context, rpcRequest rpc.R return nil, fmt.Errorf("could not get response from RPC %s: %w", r.proxyURL, err) } + span.AddEvent("response returned", trace.WithAttributes(attribute.String("body", string(resp.Body())))) + return resp, nil } } From 174911d29cfcb04dead79064e8ffdca0494551e6 Mon Sep 17 00:00:00 2001 From: abtestingalpha <104046418+abtestingalpha@users.noreply.github.com> Date: Thu, 10 Oct 2024 13:55:08 -0400 Subject: [PATCH 07/47] Updates readme (#3268) --- packages/synapse-constants/README.md | 46 ++++++++++------------------ 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/packages/synapse-constants/README.md b/packages/synapse-constants/README.md index 94f44f48c7..f0e21d4947 100644 --- a/packages/synapse-constants/README.md +++ b/packages/synapse-constants/README.md @@ -1,53 +1,41 @@ # Synapse Constants + [![npm](https://img.shields.io/npm/v/synapse-constants?style=flat-square)](https://www.npmjs.com/package/synapse-constants) This package contains the Synapse Protocol Token and Chain Constants - -# - - - ## Installation -```bash -npm install synapse-constants -``` - With Yarn: ```bash -yarn add synapse-constants +yarn add @synapsecns/synapse-constants ``` -## Usage - - -To restrict the assets and chains that are imported, you can create a "custom bridge list". From the set of all tokens imported from "bridgeable.ts" you can import specific tokens and use that as the custom list you use in your application. The same can be done for chains +## Build -## Usage -For maintenance, when new tokens are added to the bridge the following steps should be taken. +The following command will build the package locally -1. Regenerate bridgeMaps.ts - -```bash -yarn maps:generate +``` +yarn build ``` -2. Update Bridgeable.ts with the new token addresses (check all other variables like decimals/ symbols etc. ) +## Usage -3. Repackage and webpack all of the data +Importing supported tokens and chains: -```bash -yarn compile +```js +import { BRIDGABLE_TOKENS, CHAINS } from '@synapsecns/synapse-constants' ``` -4. Republish the npm package (make sure to update the version) +Importing a specific token: -```bash -npm publish +```js +import { USDC } from '@synapsecns/synapse-constants' ``` +## TODO -TODO: -- add the basic structure of the token type and the chain type to show accessibility for token logos, chain logos, and any additional information. +- [ ] Instructions on adding new chains +- [ ] Instructions on adding new tokens +- [ ] Instructions on generating new token route map From 50c1b9aac0b10dee87bed96a833b4383cdd37718 Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Thu, 10 Oct 2024 17:59:34 +0000 Subject: [PATCH 08/47] Publish - @synapsecns/bridge-docs@0.3.11 - @synapsecns/explorer-ui@0.3.11 - @synapsecns/synapse-constants@1.6.1 --- docs/bridge/CHANGELOG.md | 8 ++++++++ docs/bridge/package.json | 4 ++-- packages/explorer-ui/CHANGELOG.md | 8 ++++++++ packages/explorer-ui/package.json | 4 ++-- packages/synapse-constants/CHANGELOG.md | 8 ++++++++ packages/synapse-constants/package.json | 2 +- 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/docs/bridge/CHANGELOG.md b/docs/bridge/CHANGELOG.md index bcf598e478..6166240742 100644 --- a/docs/bridge/CHANGELOG.md +++ b/docs/bridge/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.3.11](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.3.10...@synapsecns/bridge-docs@0.3.11) (2024-10-10) + +**Note:** Version bump only for package @synapsecns/bridge-docs + + + + + ## [0.3.10](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.3.9...@synapsecns/bridge-docs@0.3.10) (2024-10-08) **Note:** Version bump only for package @synapsecns/bridge-docs diff --git a/docs/bridge/package.json b/docs/bridge/package.json index cb794cb7de..3bca31c0a8 100644 --- a/docs/bridge/package.json +++ b/docs/bridge/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/bridge-docs", - "version": "0.3.10", + "version": "0.3.11", "private": true, "scripts": { "docusaurus": "docusaurus", @@ -34,7 +34,7 @@ "@docusaurus/utils-validation": "3.5.2", "@easyops-cn/docusaurus-search-local": "^0.44.5", "@mdx-js/react": "^3.0.0", - "@synapsecns/synapse-constants": "^1.6.0", + "@synapsecns/synapse-constants": "^1.6.1", "clsx": "^2.0.0", "docusaurus-plugin-openapi-docs": "^4.0.1", "docusaurus-theme-openapi-docs": "^4.0.1", diff --git a/packages/explorer-ui/CHANGELOG.md b/packages/explorer-ui/CHANGELOG.md index bbb39b439a..d5f2f9f343 100644 --- a/packages/explorer-ui/CHANGELOG.md +++ b/packages/explorer-ui/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.3.11](https://github.com/synapsecns/sanguine/compare/@synapsecns/explorer-ui@0.3.10...@synapsecns/explorer-ui@0.3.11) (2024-10-10) + +**Note:** Version bump only for package @synapsecns/explorer-ui + + + + + ## [0.3.10](https://github.com/synapsecns/sanguine/compare/@synapsecns/explorer-ui@0.3.9...@synapsecns/explorer-ui@0.3.10) (2024-10-05) **Note:** Version bump only for package @synapsecns/explorer-ui diff --git a/packages/explorer-ui/package.json b/packages/explorer-ui/package.json index 970f75ab34..11e0aa55d7 100644 --- a/packages/explorer-ui/package.json +++ b/packages/explorer-ui/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/explorer-ui", - "version": "0.3.10", + "version": "0.3.11", "private": true, "engines": { "node": ">=18.17.0" @@ -17,7 +17,7 @@ "@mui/x-date-pickers": "^5.0.17", "@next/third-parties": "^14.2.14", "@popperjs/core": "^2.11.5", - "@synapsecns/synapse-constants": "^1.6.0", + "@synapsecns/synapse-constants": "^1.6.1", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.2.0", "@testing-library/user-event": "^13.5.0", diff --git a/packages/synapse-constants/CHANGELOG.md b/packages/synapse-constants/CHANGELOG.md index 468bb18b63..abaa6393cc 100644 --- a/packages/synapse-constants/CHANGELOG.md +++ b/packages/synapse-constants/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.6.1](https://github.com/synapsecns/sanguine/compare/@synapsecns/synapse-constants@1.6.0...@synapsecns/synapse-constants@1.6.1) (2024-10-10) + +**Note:** Version bump only for package @synapsecns/synapse-constants + + + + + # 1.6.0 (2024-10-05) diff --git a/packages/synapse-constants/package.json b/packages/synapse-constants/package.json index 37f3244327..0d9adc67f9 100644 --- a/packages/synapse-constants/package.json +++ b/packages/synapse-constants/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/synapse-constants", - "version": "1.6.0", + "version": "1.6.1", "description": "This is an npm package that maintains all synapse constants", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", From acd61de4846d9b23d7aa834b8f2eefcaae486c7d Mon Sep 17 00:00:00 2001 From: abtestingalpha <104046418+abtestingalpha@users.noreply.github.com> Date: Thu, 10 Oct 2024 15:56:39 -0400 Subject: [PATCH 09/47] feat(synapse-constants): adds preinstall step (#3269) * Adds preinstall step, ignores if `rollup` command does not exist locally * Test explorer and docs builds --- docs/bridge/README.md | 15 ++++-- packages/explorer-ui/README.md | 61 ++++--------------------- packages/synapse-constants/package.json | 1 + 3 files changed, 23 insertions(+), 54 deletions(-) diff --git a/docs/bridge/README.md b/docs/bridge/README.md index afad5c80f5..73c43b2c0e 100644 --- a/docs/bridge/README.md +++ b/docs/bridge/README.md @@ -5,17 +5,18 @@ This website is built using [Docusaurus](https://docusaurus.io/), a modern stati ## Generating API Docs + `yarn docusaurus gen-api-docs all`. ### Installation -``` +```bash $ yarn ``` ### Local Development -``` +```bash $ yarn start ``` @@ -23,8 +24,16 @@ This command starts a local development server and opens up a browser window. Mo ### Build -``` +```bash $ yarn build ``` This command generates static content into the `build` directory and can be served using any static contents hosting service. + +### Serve + +This step is needed to create a searchable index. + +```bash +$ yarn serve +``` diff --git a/packages/explorer-ui/README.md b/packages/explorer-ui/README.md index 76dc102563..31043416e4 100644 --- a/packages/explorer-ui/README.md +++ b/packages/explorer-ui/README.md @@ -1,59 +1,18 @@ # Explorer UI ## TODO: - - add readme describing explorer ui - - add integration tests -# Getting Started with Create React App +- add readme describing explorer ui +- add integration tests -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). - -## Available Scripts - -In the project directory, you can run: - -### `npm start` - -Runs the app in the development mode.\ -Open [http://localhost:3000](http://localhost:3000) to view it in your browser. - -The page will reload when you make changes.\ -You may also see any lint errors in the console. - -### `npm test` - -Launches the test runner in the interactive watch mode.\ -See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. - -### `npm run build` - -Builds the app for production to the `build` folder.\ -It correctly bundles React in production mode and optimizes the build for the best performance. - -The build is minified and the filenames include the hashes.\ -Your app is ready to be deployed! - -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. - -### `npm run eject` - -**Note: this is a one-way operation. Once you `eject`, you can't go back!** - -If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. - -Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. - -You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. - -## Learn More - -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). - -To learn React, check out the [React documentation](https://reactjs.org/). - -### Code Splitting - -This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) +## To get started +run +```bash +yarn install +``` +```bash +yarn dev +``` diff --git a/packages/synapse-constants/package.json b/packages/synapse-constants/package.json index 0d9adc67f9..12b4aaa34e 100644 --- a/packages/synapse-constants/package.json +++ b/packages/synapse-constants/package.json @@ -27,6 +27,7 @@ "lint:check": "eslint . --max-warnings=0 --config .eslintrc.cjs", "prepare": "rollup -c --bundleConfigAsCjs", "build": "rollup -c --bundleConfigAsCjs", + "preinstall": "command -v rollup >/dev/null 2>&1 && rollup -c --buildConfigAsCjs || echo 'rollup not found'", "prepublish": "yarn build", "maps:generate": "node ./src/scripts/generateMaps.cjs && node ./src/scripts/findMissing.cjs && yarn build" }, From 27019dc4e9a594553946750c9ecf47a5faf3ac80 Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Thu, 10 Oct 2024 20:00:48 +0000 Subject: [PATCH 10/47] Publish - @synapsecns/bridge-docs@0.4.0 - @synapsecns/explorer-ui@0.4.0 - @synapsecns/synapse-constants@1.7.0 --- docs/bridge/CHANGELOG.md | 11 +++++++++++ docs/bridge/package.json | 4 ++-- packages/explorer-ui/CHANGELOG.md | 11 +++++++++++ packages/explorer-ui/package.json | 4 ++-- packages/synapse-constants/CHANGELOG.md | 11 +++++++++++ packages/synapse-constants/package.json | 2 +- 6 files changed, 38 insertions(+), 5 deletions(-) diff --git a/docs/bridge/CHANGELOG.md b/docs/bridge/CHANGELOG.md index 6166240742..78e07f7024 100644 --- a/docs/bridge/CHANGELOG.md +++ b/docs/bridge/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [0.4.0](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.3.11...@synapsecns/bridge-docs@0.4.0) (2024-10-10) + + +### Features + +* **synapse-constants:** adds preinstall step ([#3269](https://github.com/synapsecns/sanguine/issues/3269)) ([acd61de](https://github.com/synapsecns/sanguine/commit/acd61de4846d9b23d7aa834b8f2eefcaae486c7d)) + + + + + ## [0.3.11](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.3.10...@synapsecns/bridge-docs@0.3.11) (2024-10-10) **Note:** Version bump only for package @synapsecns/bridge-docs diff --git a/docs/bridge/package.json b/docs/bridge/package.json index 3bca31c0a8..2d4188f108 100644 --- a/docs/bridge/package.json +++ b/docs/bridge/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/bridge-docs", - "version": "0.3.11", + "version": "0.4.0", "private": true, "scripts": { "docusaurus": "docusaurus", @@ -34,7 +34,7 @@ "@docusaurus/utils-validation": "3.5.2", "@easyops-cn/docusaurus-search-local": "^0.44.5", "@mdx-js/react": "^3.0.0", - "@synapsecns/synapse-constants": "^1.6.1", + "@synapsecns/synapse-constants": "^1.7.0", "clsx": "^2.0.0", "docusaurus-plugin-openapi-docs": "^4.0.1", "docusaurus-theme-openapi-docs": "^4.0.1", diff --git a/packages/explorer-ui/CHANGELOG.md b/packages/explorer-ui/CHANGELOG.md index d5f2f9f343..cabb762a39 100644 --- a/packages/explorer-ui/CHANGELOG.md +++ b/packages/explorer-ui/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [0.4.0](https://github.com/synapsecns/sanguine/compare/@synapsecns/explorer-ui@0.3.11...@synapsecns/explorer-ui@0.4.0) (2024-10-10) + + +### Features + +* **synapse-constants:** adds preinstall step ([#3269](https://github.com/synapsecns/sanguine/issues/3269)) ([acd61de](https://github.com/synapsecns/sanguine/commit/acd61de4846d9b23d7aa834b8f2eefcaae486c7d)) + + + + + ## [0.3.11](https://github.com/synapsecns/sanguine/compare/@synapsecns/explorer-ui@0.3.10...@synapsecns/explorer-ui@0.3.11) (2024-10-10) **Note:** Version bump only for package @synapsecns/explorer-ui diff --git a/packages/explorer-ui/package.json b/packages/explorer-ui/package.json index 11e0aa55d7..c1557a7d00 100644 --- a/packages/explorer-ui/package.json +++ b/packages/explorer-ui/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/explorer-ui", - "version": "0.3.11", + "version": "0.4.0", "private": true, "engines": { "node": ">=18.17.0" @@ -17,7 +17,7 @@ "@mui/x-date-pickers": "^5.0.17", "@next/third-parties": "^14.2.14", "@popperjs/core": "^2.11.5", - "@synapsecns/synapse-constants": "^1.6.1", + "@synapsecns/synapse-constants": "^1.7.0", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.2.0", "@testing-library/user-event": "^13.5.0", diff --git a/packages/synapse-constants/CHANGELOG.md b/packages/synapse-constants/CHANGELOG.md index abaa6393cc..67ce8de75f 100644 --- a/packages/synapse-constants/CHANGELOG.md +++ b/packages/synapse-constants/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.7.0](https://github.com/synapsecns/sanguine/compare/@synapsecns/synapse-constants@1.6.1...@synapsecns/synapse-constants@1.7.0) (2024-10-10) + + +### Features + +* **synapse-constants:** adds preinstall step ([#3269](https://github.com/synapsecns/sanguine/issues/3269)) ([acd61de](https://github.com/synapsecns/sanguine/commit/acd61de4846d9b23d7aa834b8f2eefcaae486c7d)) + + + + + ## [1.6.1](https://github.com/synapsecns/sanguine/compare/@synapsecns/synapse-constants@1.6.0...@synapsecns/synapse-constants@1.6.1) (2024-10-10) **Note:** Version bump only for package @synapsecns/synapse-constants diff --git a/packages/synapse-constants/package.json b/packages/synapse-constants/package.json index 12b4aaa34e..42c99d8383 100644 --- a/packages/synapse-constants/package.json +++ b/packages/synapse-constants/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/synapse-constants", - "version": "1.6.1", + "version": "1.7.0", "description": "This is an npm package that maintains all synapse constants", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", From 2c90cf74e4b77ff943a835f4f7a6ce14d3d66e46 Mon Sep 17 00:00:00 2001 From: abtestingalpha <104046418+abtestingalpha@users.noreply.github.com> Date: Fri, 11 Oct 2024 08:08:44 -0400 Subject: [PATCH 11/47] Checks for existence of bridgeTransactions field (#3270) --- packages/rest-api/src/controllers/destinationTxController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rest-api/src/controllers/destinationTxController.ts b/packages/rest-api/src/controllers/destinationTxController.ts index dc951976d8..abc3b9e1e9 100644 --- a/packages/rest-api/src/controllers/destinationTxController.ts +++ b/packages/rest-api/src/controllers/destinationTxController.ts @@ -46,7 +46,7 @@ export const destinationTxController = async (req, res) => { }) const graphqlData = await graphqlResponse.json() - const toInfo = graphqlData.data.bridgeTransactions[0]?.toInfo || null + const toInfo = graphqlData.data.bridgeTransactions?.[0]?.toInfo || null if (toInfo) { const { tokenAddress, value, chainID, ...restToInfo } = toInfo From 9e5340b4cb44a881dcfa9e18961c4fee79899fe6 Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Fri, 11 Oct 2024 12:13:08 +0000 Subject: [PATCH 12/47] Publish - @synapsecns/rest-api@1.4.7 --- packages/rest-api/CHANGELOG.md | 8 ++++++++ packages/rest-api/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/rest-api/CHANGELOG.md b/packages/rest-api/CHANGELOG.md index a1aea8c252..bd7092138d 100644 --- a/packages/rest-api/CHANGELOG.md +++ b/packages/rest-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.4.7](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.4.6...@synapsecns/rest-api@1.4.7) (2024-10-11) + +**Note:** Version bump only for package @synapsecns/rest-api + + + + + ## [1.4.6](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.4.5...@synapsecns/rest-api@1.4.6) (2024-10-10) **Note:** Version bump only for package @synapsecns/rest-api diff --git a/packages/rest-api/package.json b/packages/rest-api/package.json index 277a49c31b..bd70ad3602 100644 --- a/packages/rest-api/package.json +++ b/packages/rest-api/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/rest-api", - "version": "1.4.6", + "version": "1.4.7", "private": "true", "engines": { "node": ">=18.17.0" From 12fb1e53d5dddd70b41623f38cb0198bf91fa22b Mon Sep 17 00:00:00 2001 From: abtestingalpha <104046418+abtestingalpha@users.noreply.github.com> Date: Fri, 11 Oct 2024 09:03:41 -0400 Subject: [PATCH 13/47] Adds chain validation for swap (#3271) --- packages/rest-api/src/constants/index.ts | 21 +++++++++++++++++++ packages/rest-api/src/routes/swapRoute.ts | 12 +++++++++-- packages/rest-api/src/tests/swapRoute.test.ts | 17 ++++++++++++++- .../src/validations/validSwapChain.ts | 5 +++++ .../{validSwap.ts => validSwapTokens.ts} | 2 +- 5 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 packages/rest-api/src/validations/validSwapChain.ts rename packages/rest-api/src/validations/{validSwap.ts => validSwapTokens.ts} (92%) diff --git a/packages/rest-api/src/constants/index.ts b/packages/rest-api/src/constants/index.ts index c136beb9fa..12a3cb05a3 100644 --- a/packages/rest-api/src/constants/index.ts +++ b/packages/rest-api/src/constants/index.ts @@ -1,3 +1,5 @@ +import { CHAINS } from './chains' + export const VALID_BRIDGE_MODULES = [ 'SynapseBridge', 'SynapseCCTP', @@ -6,3 +8,22 @@ export const VALID_BRIDGE_MODULES = [ export const ZeroAddress = '0x0000000000000000000000000000000000000000' export const NativeGasAddress = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' + +export const SUPPORTED_SWAP_CHAIN_IDS = [ + CHAINS.ARBITRUM.id, + CHAINS.AURORA.id, + CHAINS.AVALANCHE.id, + CHAINS.BASE.id, + CHAINS.BLAST.id, + CHAINS.BNBCHAIN.id, + CHAINS.BOBA.id, + CHAINS.CANTO.id, + CHAINS.CRONOS.id, + CHAINS.ETHEREUM.id, + CHAINS.FANTOM.id, + CHAINS.HARMONY.id, + CHAINS.KLAYTN.id, + CHAINS.METIS.id, + CHAINS.OPTIMISM.id, + CHAINS.POLYGON.id, +] diff --git a/packages/rest-api/src/routes/swapRoute.ts b/packages/rest-api/src/routes/swapRoute.ts index 6eef6a67f9..5f8bb04277 100644 --- a/packages/rest-api/src/routes/swapRoute.ts +++ b/packages/rest-api/src/routes/swapRoute.ts @@ -8,7 +8,8 @@ import { isTokenAddress } from '../utils/isTokenAddress' import { isTokenSupportedOnChain } from '../utils/isTokenSupportedOnChain' import { checksumAddresses } from '../middleware/checksumAddresses' import { normalizeNativeTokenAddress } from '../middleware/normalizeNativeTokenAddress' -import { validSwap } from '../validations/validSwap' +import { validSwapTokens } from '../validations/validSwapTokens' +import { validSwapChain } from '../validations/validSwapChain' const router = express.Router() @@ -163,11 +164,18 @@ router.get( ) .withMessage('Token not supported on specified chain'), check('amount').exists().withMessage('amount is required').isNumeric(), + check() + .custom((_value, { req }) => { + const { chain } = req.query + + return validSwapChain(chain) + }) + .withMessage('Swap not supported for given chain'), check() .custom((_value, { req }) => { const { chain, fromToken, toToken } = req.query - return validSwap(chain, fromToken, toToken) + return validSwapTokens(chain, fromToken, toToken) }) .withMessage('Swap not supported for given tokens'), ], diff --git a/packages/rest-api/src/tests/swapRoute.test.ts b/packages/rest-api/src/tests/swapRoute.test.ts index c849475cc1..9c09f89a22 100644 --- a/packages/rest-api/src/tests/swapRoute.test.ts +++ b/packages/rest-api/src/tests/swapRoute.test.ts @@ -3,7 +3,7 @@ import express from 'express' import swapRoute from '../routes/swapRoute' import { NativeGasAddress, ZeroAddress } from '../constants' -import { DAI, ETH, NETH, USDC } from '../constants/bridgeable' +import { DAI, ETH, NETH, USDC, USDT } from '../constants/bridgeable' const app = express() app.use('/swap', swapRoute) @@ -78,6 +78,21 @@ describe('Swap Route with Real Synapse Service', () => { ) }, 10_000) + it('should return 400 for swap on unsupported chain', async () => { + const response = await request(app).get('/swap').query({ + chain: '59144', + fromToken: USDC.addresses[59144], + toToken: USDT.addresses[59144], + amount: '1000', + }) + + expect(response.status).toBe(400) + expect(response.body.error).toHaveProperty( + 'message', + 'Swap not supported for given chain' + ) + }) + it('should return 400 for invalid fromToken + toToken combo', async () => { const response = await request(app).get('/swap').query({ chain: '1', diff --git a/packages/rest-api/src/validations/validSwapChain.ts b/packages/rest-api/src/validations/validSwapChain.ts new file mode 100644 index 0000000000..47c56c87c9 --- /dev/null +++ b/packages/rest-api/src/validations/validSwapChain.ts @@ -0,0 +1,5 @@ +import { SUPPORTED_SWAP_CHAIN_IDS } from '../constants' + +export const validSwapChain = (chain: number | string) => { + return SUPPORTED_SWAP_CHAIN_IDS.includes(Number(chain)) +} diff --git a/packages/rest-api/src/validations/validSwap.ts b/packages/rest-api/src/validations/validSwapTokens.ts similarity index 92% rename from packages/rest-api/src/validations/validSwap.ts rename to packages/rest-api/src/validations/validSwapTokens.ts index 576cd23b80..797ae24279 100644 --- a/packages/rest-api/src/validations/validSwap.ts +++ b/packages/rest-api/src/validations/validSwapTokens.ts @@ -1,6 +1,6 @@ import { tokenAddressToToken } from '../utils/tokenAddressToToken' -export const validSwap = ( +export const validSwapTokens = ( chain: number | string, fromToken: string, toToken: string From 34f5ff58bfdf26f5f3609f69195ff350edaa593a Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Fri, 11 Oct 2024 13:08:13 +0000 Subject: [PATCH 14/47] Publish - @synapsecns/rest-api@1.4.8 --- packages/rest-api/CHANGELOG.md | 8 ++++++++ packages/rest-api/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/rest-api/CHANGELOG.md b/packages/rest-api/CHANGELOG.md index bd7092138d..87b856c21f 100644 --- a/packages/rest-api/CHANGELOG.md +++ b/packages/rest-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.4.8](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.4.7...@synapsecns/rest-api@1.4.8) (2024-10-11) + +**Note:** Version bump only for package @synapsecns/rest-api + + + + + ## [1.4.7](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.4.6...@synapsecns/rest-api@1.4.7) (2024-10-11) **Note:** Version bump only for package @synapsecns/rest-api diff --git a/packages/rest-api/package.json b/packages/rest-api/package.json index bd70ad3602..3d107ce2d5 100644 --- a/packages/rest-api/package.json +++ b/packages/rest-api/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/rest-api", - "version": "1.4.7", + "version": "1.4.8", "private": "true", "engines": { "node": ">=18.17.0" From bd8b45af0735c9e763be183163db003a00312e52 Mon Sep 17 00:00:00 2001 From: abtestingalpha <104046418+abtestingalpha@users.noreply.github.com> Date: Fri, 11 Oct 2024 11:02:32 -0400 Subject: [PATCH 15/47] Adds World Chain (#3272) --- packages/sdk-router/src/constants/chainIds.ts | 3 +++ packages/sdk-router/src/constants/medianTime.ts | 1 + 2 files changed, 4 insertions(+) diff --git a/packages/sdk-router/src/constants/chainIds.ts b/packages/sdk-router/src/constants/chainIds.ts index 2a3846c3c7..b3fe066cfe 100644 --- a/packages/sdk-router/src/constants/chainIds.ts +++ b/packages/sdk-router/src/constants/chainIds.ts @@ -6,6 +6,7 @@ export enum SupportedChainId { POLYGON = 137, FANTOM = 250, BOBA = 288, + WORLDCHAIN = 480, METIS = 1088, MOONBEAM = 1284, MOONRIVER = 1285, @@ -29,6 +30,7 @@ export enum SupportedChainId { const UNSUPPORTED_BRIDGE_CHAIN_IDS: number[] = [ SupportedChainId.LINEA, SupportedChainId.SCROLL, + SupportedChainId.WORLDCHAIN, ] /** @@ -62,6 +64,7 @@ export const RFQ_SUPPORTED_CHAIN_IDS: number[] = [ SupportedChainId.ETH, SupportedChainId.OPTIMISM, SupportedChainId.BSC, + SupportedChainId.WORLDCHAIN, SupportedChainId.BASE, SupportedChainId.ARBITRUM, SupportedChainId.LINEA, diff --git a/packages/sdk-router/src/constants/medianTime.ts b/packages/sdk-router/src/constants/medianTime.ts index 08d7cf8cf6..19184d9422 100644 --- a/packages/sdk-router/src/constants/medianTime.ts +++ b/packages/sdk-router/src/constants/medianTime.ts @@ -54,4 +54,5 @@ export const MEDIAN_TIME_RFQ = { [SupportedChainId.LINEA]: 15, [SupportedChainId.BLAST]: 15, [SupportedChainId.SCROLL]: 15, + [SupportedChainId.WORLDCHAIN]: 15, } From 1f61284ba5dada8df684250a86e5f9ed58c1bd1d Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Fri, 11 Oct 2024 15:06:45 +0000 Subject: [PATCH 16/47] Publish - @synapsecns/rest-api@1.4.9 - @synapsecns/sdk-router@0.11.4 - @synapsecns/synapse-interface@0.40.8 - @synapsecns/widget@0.7.4 --- packages/rest-api/CHANGELOG.md | 8 ++++++++ packages/rest-api/package.json | 4 ++-- packages/sdk-router/CHANGELOG.md | 8 ++++++++ packages/sdk-router/package.json | 2 +- packages/synapse-interface/CHANGELOG.md | 8 ++++++++ packages/synapse-interface/package.json | 4 ++-- packages/widget/CHANGELOG.md | 8 ++++++++ packages/widget/package.json | 4 ++-- 8 files changed, 39 insertions(+), 7 deletions(-) diff --git a/packages/rest-api/CHANGELOG.md b/packages/rest-api/CHANGELOG.md index 87b856c21f..6c309e2a1b 100644 --- a/packages/rest-api/CHANGELOG.md +++ b/packages/rest-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.4.9](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.4.8...@synapsecns/rest-api@1.4.9) (2024-10-11) + +**Note:** Version bump only for package @synapsecns/rest-api + + + + + ## [1.4.8](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.4.7...@synapsecns/rest-api@1.4.8) (2024-10-11) **Note:** Version bump only for package @synapsecns/rest-api diff --git a/packages/rest-api/package.json b/packages/rest-api/package.json index 3d107ce2d5..38b029d3d3 100644 --- a/packages/rest-api/package.json +++ b/packages/rest-api/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/rest-api", - "version": "1.4.8", + "version": "1.4.9", "private": "true", "engines": { "node": ">=18.17.0" @@ -22,7 +22,7 @@ "@ethersproject/bignumber": "^5.7.0", "@ethersproject/providers": "^5.7.2", "@ethersproject/units": "5.7.0", - "@synapsecns/sdk-router": "^0.11.3", + "@synapsecns/sdk-router": "^0.11.4", "bignumber": "^1.1.0", "ethers": "5.7.2", "express": "^4.18.2", diff --git a/packages/sdk-router/CHANGELOG.md b/packages/sdk-router/CHANGELOG.md index d8b4f3c109..a75b014286 100644 --- a/packages/sdk-router/CHANGELOG.md +++ b/packages/sdk-router/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.11.4](https://github.com/synapsecns/sanguine/compare/@synapsecns/sdk-router@0.11.3...@synapsecns/sdk-router@0.11.4) (2024-10-11) + +**Note:** Version bump only for package @synapsecns/sdk-router + + + + + ## [0.11.3](https://github.com/synapsecns/sanguine/compare/@synapsecns/sdk-router@0.11.2...@synapsecns/sdk-router@0.11.3) (2024-10-03) diff --git a/packages/sdk-router/package.json b/packages/sdk-router/package.json index a5e8afaf28..520390b750 100644 --- a/packages/sdk-router/package.json +++ b/packages/sdk-router/package.json @@ -1,7 +1,7 @@ { "name": "@synapsecns/sdk-router", "description": "An SDK for interacting with the Synapse Protocol", - "version": "0.11.3", + "version": "0.11.4", "license": "MIT", "main": "dist/index.js", "typings": "dist/index.d.ts", diff --git a/packages/synapse-interface/CHANGELOG.md b/packages/synapse-interface/CHANGELOG.md index 655b63c5e5..0895428ebb 100644 --- a/packages/synapse-interface/CHANGELOG.md +++ b/packages/synapse-interface/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.40.8](https://github.com/synapsecns/sanguine/compare/@synapsecns/synapse-interface@0.40.7...@synapsecns/synapse-interface@0.40.8) (2024-10-11) + +**Note:** Version bump only for package @synapsecns/synapse-interface + + + + + ## [0.40.7](https://github.com/synapsecns/sanguine/compare/@synapsecns/synapse-interface@0.40.6...@synapsecns/synapse-interface@0.40.7) (2024-10-09) **Note:** Version bump only for package @synapsecns/synapse-interface diff --git a/packages/synapse-interface/package.json b/packages/synapse-interface/package.json index d890df2885..0efdd27a49 100644 --- a/packages/synapse-interface/package.json +++ b/packages/synapse-interface/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/synapse-interface", - "version": "0.40.7", + "version": "0.40.8", "private": true, "engines": { "node": ">=18.18.0" @@ -38,7 +38,7 @@ "@reduxjs/toolkit": "^1.9.5", "@rtk-query/graphql-request-base-query": "^2.2.0", "@segment/analytics-next": "^1.53.0", - "@synapsecns/sdk-router": "^0.11.3", + "@synapsecns/sdk-router": "^0.11.4", "@tailwindcss/aspect-ratio": "^0.4.2", "@tailwindcss/forms": "^0.5.3", "@tailwindcss/typography": "^0.5.9", diff --git a/packages/widget/CHANGELOG.md b/packages/widget/CHANGELOG.md index 9cab7694db..f50c33cd7e 100644 --- a/packages/widget/CHANGELOG.md +++ b/packages/widget/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.7.4](https://github.com/synapsecns/sanguine/compare/@synapsecns/widget@0.7.3...@synapsecns/widget@0.7.4) (2024-10-11) + +**Note:** Version bump only for package @synapsecns/widget + + + + + ## [0.7.3](https://github.com/synapsecns/sanguine/compare/@synapsecns/widget@0.7.2...@synapsecns/widget@0.7.3) (2024-10-03) **Note:** Version bump only for package @synapsecns/widget diff --git a/packages/widget/package.json b/packages/widget/package.json index a9af018a9b..8d5e6de077 100644 --- a/packages/widget/package.json +++ b/packages/widget/package.json @@ -1,7 +1,7 @@ { "name": "@synapsecns/widget", "description": "Widget library for interacting with the Synapse Protocol", - "version": "0.7.3", + "version": "0.7.4", "license": "MIT", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", @@ -68,7 +68,7 @@ "@ethersproject/providers": "^5.7.2", "@ethersproject/units": "^5.7.0", "@reduxjs/toolkit": "^2.0.1", - "@synapsecns/sdk-router": "^0.11.3", + "@synapsecns/sdk-router": "^0.11.4", "ethers": "^6.9.1", "lodash": "^4.17.21", "react-redux": "^9.0.2" From 0428f30dfac43f0b57d12c6a2c129b27bee02e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CF=87=C2=B2?= <88190723+ChiTimesChi@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:09:28 +0100 Subject: [PATCH 17/47] test(contracts-rfq): gas benchmark for the arbitrary call [SLT-233] (#3273) * test: gas bench for bridge with arbitrary call * refactor: deduplicate checks * fix: gas benchmark contract names * test: gas benchmark for relay with arbitrary call * test: separate set of cases for bridge/prove/claim with arbitrary calls * fix: start from nonce=1 in gas benchmark tests --- ...tBridgeV2.GasBench.Dst.ArbitraryCall.t.sol | 28 +++++++++++ .../test/FastBridgeV2.GasBench.Dst.Excl.t.sol | 5 +- .../test/FastBridgeV2.GasBench.Dst.t.sol | 2 +- .../test/FastBridgeV2.GasBench.Encoding.t.sol | 9 ++-- ...tBridgeV2.GasBench.Src.ArbitraryCall.t.sol | 18 +++++++ .../FastBridgeV2.GasBench.Src.PFees.t.sol | 10 ++-- .../test/FastBridgeV2.GasBench.Src.t.sol | 50 +++++++++++-------- .../contracts-rfq/test/FastBridgeV2.t.sol | 4 ++ 8 files changed, 94 insertions(+), 32 deletions(-) create mode 100644 packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.ArbitraryCall.t.sol create mode 100644 packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.ArbitraryCall.t.sol diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.ArbitraryCall.t.sol new file mode 100644 index 0000000000..1fe2da38ab --- /dev/null +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.ArbitraryCall.t.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {FastBridgeV2GasBenchmarkDstTest} from "./FastBridgeV2.GasBench.Dst.t.sol"; +import {RecipientMock} from "./mocks/RecipientMock.sol"; + +// solhint-disable func-name-mixedcase, ordering +contract FastBridgeV2GasBenchmarkDstArbitraryCallTest is FastBridgeV2GasBenchmarkDstTest { + // To get an idea about how much overhead the arbitrary call adds to the relaying process, we use a mock + // recipient that has the hook function implemented as a no-op. + // The mocked callParams are chosen to be similar to the real use cases: + // - user address + // - some kind of ID to decide what to do with the tokens next + + function setUp() public virtual override { + // In the inherited tests userB is always used as the recipient of the tokens. + userB = address(new RecipientMock()); + vm.label(userB, "ContractRecipient"); + super.setUp(); + } + + function createFixturesV2() public virtual override { + super.createFixturesV2(); + bytes memory mockCallParams = abi.encode(userA, keccak256("Random ID")); + setTokenTestCallParams(mockCallParams); + setEthTestCallParams(mockCallParams); + } +} diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.Excl.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.Excl.t.sol index eae0dffaa1..685dab76a4 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.Excl.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.Excl.t.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {FastBridgeV2DstGasBenchmarkTest} from "./FastBridgeV2.GasBench.Dst.t.sol"; +import {FastBridgeV2GasBenchmarkDstTest} from "./FastBridgeV2.GasBench.Dst.t.sol"; // solhint-disable func-name-mixedcase, ordering -contract FastBridgeV2DstExclusivityTest is FastBridgeV2DstGasBenchmarkTest { +contract FastBridgeV2GasBenchmarkDstExclusivityTest is FastBridgeV2GasBenchmarkDstTest { uint256 public constant EXCLUSIVITY_PERIOD = 60 seconds; function setUp() public virtual override { @@ -13,6 +13,7 @@ contract FastBridgeV2DstExclusivityTest is FastBridgeV2DstGasBenchmarkTest { } function createFixturesV2() public virtual override { + super.createFixturesV2(); setTokenTestExclusivityParams(relayerA, EXCLUSIVITY_PERIOD); setEthTestExclusivityParams(relayerA, EXCLUSIVITY_PERIOD); } diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.t.sol index 6afabce02e..8c739ad14b 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.t.sol @@ -6,7 +6,7 @@ import {FastBridgeV2DstBaseTest} from "./FastBridgeV2.Dst.Base.t.sol"; // solhint-disable func-name-mixedcase, ordering /// @notice This test is used to estimate the gas cost of FastBridgeV2 destination chain functions. /// Very little state checks are performed, make sure to do full coverage in different tests. -contract FastBridgeV2DstGasBenchmarkTest is FastBridgeV2DstBaseTest { +contract FastBridgeV2GasBenchmarkDstTest is FastBridgeV2DstBaseTest { uint256 public constant INITIAL_USER_BALANCE = 100 ether; function mintTokens() public virtual override { diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Encoding.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Encoding.t.sol index 703e73267b..e8bdb2a8b9 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Encoding.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Encoding.t.sol @@ -4,9 +4,7 @@ pragma solidity ^0.8.20; import {FastBridgeV2SrcBaseTest} from "./FastBridgeV2.Src.Base.t.sol"; // solhint-disable func-name-mixedcase, ordering -contract FastBridgeV2GasBenchmarkSrcProtocolFeesTest is FastBridgeV2SrcBaseTest { - // TODO: add more tests with variable length requests once arbitrary call is done - +contract FastBridgeV2GasBenchmarkEncodingTest is FastBridgeV2SrcBaseTest { function test_getBridgeTransaction() public view { bytes memory request = abi.encode(extractV1(tokenTx)); fastBridge.getBridgeTransaction(request); @@ -16,4 +14,9 @@ contract FastBridgeV2GasBenchmarkSrcProtocolFeesTest is FastBridgeV2SrcBaseTest bytes memory request = abi.encode(tokenTx); fastBridge.getBridgeTransactionV2(request); } + + function test_getBridgeTransactionV2_withArbitraryCall() public { + setTokenTestCallParams({callParams: abi.encode(userA, keccak256("Random ID"))}); + test_getBridgeTransactionV2(); + } } diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.ArbitraryCall.t.sol new file mode 100644 index 0000000000..e806f27544 --- /dev/null +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.ArbitraryCall.t.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {FastBridgeV2GasBenchmarkSrcTest} from "./FastBridgeV2.GasBench.Src.t.sol"; + +// solhint-disable func-name-mixedcase, ordering +contract FastBridgeV2GasBenchmarkSrcArbitraryCallTest is FastBridgeV2GasBenchmarkSrcTest { + function createFixturesV2() public virtual override { + super.createFixturesV2(); + bytes memory mockCallParams = abi.encode(userA, keccak256("Random ID")); + setTokenTestCallParams(mockCallParams); + setEthTestCallParams(mockCallParams); + bridgedTokenTx.callParams = mockCallParams; + bridgedEthTx.callParams = mockCallParams; + provenTokenTx.callParams = mockCallParams; + provenEthTx.callParams = mockCallParams; + } +} diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.PFees.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.PFees.t.sol index 77b439d18e..51f17b5a96 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.PFees.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.PFees.t.sol @@ -27,10 +27,10 @@ contract FastBridgeV2GasBenchmarkSrcProtocolFeesTest is FastBridgeV2GasBenchmark provenTokenTx = tokenTx; bridgedEthTx = ethTx; provenEthTx = ethTx; - - bridgedTokenTx.nonce = 0; - bridgedEthTx.nonce = 1; - provenTokenTx.nonce = 2; - provenEthTx.nonce = 3; + // See FastBridgeV2GasBenchmarkSrcTest.initExistingTxs for why these start from 1, not 0 + bridgedTokenTx.nonce = 1; + bridgedEthTx.nonce = 2; + provenTokenTx.nonce = 3; + provenEthTx.nonce = 4; } } diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.t.sol index 0b6834d6ff..940eae3aa1 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.t.sol @@ -38,13 +38,14 @@ contract FastBridgeV2GasBenchmarkSrcTest is FastBridgeV2SrcBaseTest { bridgedEthTx = ethTx; provenEthTx = ethTx; - bridgedTokenTx.nonce = 0; - bridgedEthTx.nonce = 1; - provenTokenTx.nonce = 2; - provenEthTx.nonce = 3; - // Next nonce for userA tx would be 4 (either token or eth) - tokenTx.nonce = 4; - ethTx.nonce = 4; + // See initExistingTxs for why these start from 1, not 0 + bridgedTokenTx.nonce = 1; + bridgedEthTx.nonce = 2; + provenTokenTx.nonce = 3; + provenEthTx.nonce = 4; + // Next nonce for userA tx would be 5 (either token or eth) + tokenTx.nonce = 5; + ethTx.nonce = 5; } function createFixturesV2() public virtual override { @@ -67,10 +68,13 @@ contract FastBridgeV2GasBenchmarkSrcTest is FastBridgeV2SrcBaseTest { } function initExistingTxs() public { - bridge({caller: userA, msgValue: 0, params: tokenParams}); - bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams}); - bridge({caller: userA, msgValue: 0, params: tokenParams}); - bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams}); + // Set userA nonce to 1 so that the first bridge tx doesn't have inflated gas costs due to + // the storage write from the zero initial value + cheatSenderNonce(userA, 1); + bridge({caller: userA, msgValue: 0, params: tokenParams, paramsV2: tokenParamsV2}); + bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + bridge({caller: userA, msgValue: 0, params: tokenParams, paramsV2: tokenParamsV2}); + bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); skipBlocksExactly(1); prove({caller: relayerA, bridgeTx: provenTokenTx, destTxHash: hex"01"}); prove({caller: relayerB, transactionId: getTxId(provenEthTx), destTxHash: hex"02", relayer: relayerA}); @@ -96,19 +100,21 @@ contract FastBridgeV2GasBenchmarkSrcTest is FastBridgeV2SrcBaseTest { // ═══════════════════════════════════════════════════ TOKEN ═══════════════════════════════════════════════════════ - function test_bridge_token() public { - bridge({caller: userA, msgValue: 0, params: tokenParams}); + function checkAfterBridgeToken() public view { assertEq(fastBridge.bridgeStatuses(getTxId(tokenTx)), IFastBridgeV2.BridgeStatus.REQUESTED); assertEq(srcToken.balanceOf(userA), initialUserBalanceToken - tokenParams.originAmount); assertEq(srcToken.balanceOf(address(fastBridge)), initialFastBridgeBalanceToken + tokenParams.originAmount); } + function test_bridge_token() public { + bridge({caller: userA, msgValue: 0, params: tokenParams, paramsV2: tokenParamsV2}); + checkAfterBridgeToken(); + } + function test_bridge_token_withExclusivity() public { setTokenTestExclusivityParams(relayerA, EXCLUSIVITY_PERIOD); bridge({caller: userA, msgValue: 0, params: tokenParams, paramsV2: tokenParamsV2}); - assertEq(fastBridge.bridgeStatuses(getTxId(tokenTx)), IFastBridgeV2.BridgeStatus.REQUESTED); - assertEq(srcToken.balanceOf(userA), initialUserBalanceToken - tokenParams.originAmount); - assertEq(srcToken.balanceOf(address(fastBridge)), initialFastBridgeBalanceToken + tokenParams.originAmount); + checkAfterBridgeToken(); } function test_prove_token() public { @@ -177,19 +183,21 @@ contract FastBridgeV2GasBenchmarkSrcTest is FastBridgeV2SrcBaseTest { // ════════════════════════════════════════════════════ ETH ════════════════════════════════════════════════════════ - function test_bridge_eth() public { - bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams}); + function checkAfterBridgeEth() public view { assertEq(fastBridge.bridgeStatuses(getTxId(ethTx)), IFastBridgeV2.BridgeStatus.REQUESTED); assertEq(userA.balance, initialUserBalanceEth - ethParams.originAmount); assertEq(address(fastBridge).balance, initialFastBridgeBalanceEth + ethParams.originAmount); } + function test_bridge_eth() public { + bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + checkAfterBridgeEth(); + } + function test_bridge_eth_withExclusivity() public { setEthTestExclusivityParams(relayerA, EXCLUSIVITY_PERIOD); bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); - assertEq(fastBridge.bridgeStatuses(getTxId(ethTx)), IFastBridgeV2.BridgeStatus.REQUESTED); - assertEq(userA.balance, initialUserBalanceEth - ethParams.originAmount); - assertEq(address(fastBridge).balance, initialFastBridgeBalanceEth + ethParams.originAmount); + checkAfterBridgeEth(); } function test_prove_eth() public { diff --git a/packages/contracts-rfq/test/FastBridgeV2.t.sol b/packages/contracts-rfq/test/FastBridgeV2.t.sol index 8011f8a8e2..e195d8fabf 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.t.sol @@ -231,4 +231,8 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { function cheatCollectedProtocolFees(address token, uint256 amount) public { stdstore.target(address(fastBridge)).sig("protocolFees(address)").with_key(token).checked_write(amount); } + + function cheatSenderNonce(address sender, uint256 nonce) public { + stdstore.target(address(fastBridge)).sig("senderNonces(address)").with_key(sender).checked_write(nonce); + } } From aac31794bf6f624cb96cff31a6703e57cc2c2852 Mon Sep 17 00:00:00 2001 From: ChiTimesChi Date: Fri, 11 Oct 2024 15:13:38 +0000 Subject: [PATCH 18/47] Publish - @synapsecns/contracts-rfq@0.7.3 --- packages/contracts-rfq/CHANGELOG.md | 8 ++++++++ packages/contracts-rfq/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/contracts-rfq/CHANGELOG.md b/packages/contracts-rfq/CHANGELOG.md index 2590c00289..de399bd2ae 100644 --- a/packages/contracts-rfq/CHANGELOG.md +++ b/packages/contracts-rfq/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.7.3](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.7.2...@synapsecns/contracts-rfq@0.7.3) (2024-10-11) + +**Note:** Version bump only for package @synapsecns/contracts-rfq + + + + + ## [0.7.2](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.7.1...@synapsecns/contracts-rfq@0.7.2) (2024-10-09) diff --git a/packages/contracts-rfq/package.json b/packages/contracts-rfq/package.json index b9eda08002..dc5bd9c504 100644 --- a/packages/contracts-rfq/package.json +++ b/packages/contracts-rfq/package.json @@ -1,7 +1,7 @@ { "name": "@synapsecns/contracts-rfq", "license": "MIT", - "version": "0.7.2", + "version": "0.7.3", "description": "FastBridge contracts.", "private": true, "files": [ From 8b54b4403d30a4625a7c9cdd9fbc60dab5b15318 Mon Sep 17 00:00:00 2001 From: aureliusbtc <82057759+aureliusbtc@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:49:19 -0500 Subject: [PATCH 19/47] update bl --- packages/synapse-interface/public/blacklist.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/synapse-interface/public/blacklist.json b/packages/synapse-interface/public/blacklist.json index d4efb6cf64..77ae62f303 100644 --- a/packages/synapse-interface/public/blacklist.json +++ b/packages/synapse-interface/public/blacklist.json @@ -552,5 +552,6 @@ "0x408d8e12c7ed8e5a7291fbD5E6164f41ecdA6B46", "0x278dF4492d16321b247660799FAD1A12dE152Dd1", "0x551BE68Cdf9Ce453ead61097649C34196d0bDb27", - "0x12AE4569d0e2B01857eD96D98cd4C9b09f21CA8b" + "0x12AE4569d0e2B01857eD96D98cd4C9b09f21CA8b", + "0x8bFE38d7c70F8953e701149E448c03E29ECcd4b0" ] From bedbf2d6ce6fda06fc0754a8182de27fae2425aa Mon Sep 17 00:00:00 2001 From: aureliusbtc <82057759+aureliusbtc@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:49:55 -0500 Subject: [PATCH 20/47] update bl --- packages/synapse-interface/public/blacklist.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/synapse-interface/public/blacklist.json b/packages/synapse-interface/public/blacklist.json index 77ae62f303..f018d998e9 100644 --- a/packages/synapse-interface/public/blacklist.json +++ b/packages/synapse-interface/public/blacklist.json @@ -553,5 +553,9 @@ "0x278dF4492d16321b247660799FAD1A12dE152Dd1", "0x551BE68Cdf9Ce453ead61097649C34196d0bDb27", "0x12AE4569d0e2B01857eD96D98cd4C9b09f21CA8b", - "0x8bFE38d7c70F8953e701149E448c03E29ECcd4b0" + "0x8bFE38d7c70F8953e701149E448c03E29ECcd4b0", + "0x6fdb264a876c811c7e101ee7a4f4fe7704ecbb72", + "0xb584050909a300fa0306b29f72e63dc4615b6f53", + "0xA963df55B326609a0cd205e85ca92d2a3c94DaB5", + "0x0605eDeE6a8b8b553caE09Abe83b2ebeb75516eC" ] From 099624f805208fe7c7ad834e3f6d2335d9bffa50 Mon Sep 17 00:00:00 2001 From: dwasse Date: Fri, 11 Oct 2024 12:03:10 -0500 Subject: [PATCH 21/47] feat(rfq-relayer): forward bridge requests in new goroutine (#3276) * Feat: call Forward in new goroutine in handleBridgeRequestedLog * [goreleaser] --- services/rfq/relayer/service/handlers.go | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/services/rfq/relayer/service/handlers.go b/services/rfq/relayer/service/handlers.go index fc1bc1abe8..dbba3dea6e 100644 --- a/services/rfq/relayer/service/handlers.go +++ b/services/rfq/relayer/service/handlers.go @@ -47,7 +47,12 @@ func (r *Relayer) handleBridgeRequestedLog(parentCtx context.Context, req *fastb return nil } - defer unlocker.Unlock() + shouldUnlock := true + defer func() { + if shouldUnlock { + unlocker.Unlock() + } + }() _, err = r.db.GetQuoteRequestByID(ctx, req.TransactionId) // expect no results @@ -120,12 +125,17 @@ func (r *Relayer) handleBridgeRequestedLog(parentCtx context.Context, req *fastb if err != nil { return fmt.Errorf("could not get quote request handler: %w", err) } - // Forward instead of lock since we called lock above. - fwdErr := qr.Forward(ctx, dbReq) - if fwdErr != nil { - logger.Errorf("could not forward to handle seen: %w", fwdErr) - span.AddEvent("could not forward to handle seen") - } + + // Forward in new goroutine and retain the lock. + shouldUnlock = false + go func() { + defer unlocker.Unlock() + fwdErr := qr.Forward(ctx, dbReq) + if fwdErr != nil { + logger.Errorf("could not forward to handle seen: %w", fwdErr) + span.AddEvent(fmt.Sprintf("could not forward to handle seen: %s", fwdErr.Error())) + } + }() return nil } From 69c462174e3ac59901512f527422300f77b06a05 Mon Sep 17 00:00:00 2001 From: trajan0x <83933037+trajan0x@users.noreply.github.com> Date: Sat, 12 Oct 2024 10:10:19 -0400 Subject: [PATCH 22/47] move docs [SLT-133] (#3278) * move docs * content cleanup --------- Co-authored-by: Trajan0x --- docs/bridge/docusaurus.config.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/bridge/docusaurus.config.ts b/docs/bridge/docusaurus.config.ts index cd3586dbac..f296f4e05a 100644 --- a/docs/bridge/docusaurus.config.ts +++ b/docs/bridge/docusaurus.config.ts @@ -91,9 +91,8 @@ const config: Config = { // Replace with your project's social card image: 'img/docusaurus-social-card.jpg', announcementBar: { - id: 'announcementBar-v3.2', // Increment on change + // id: 'announcementBar-v3.2', // Increment on change // content: `⭐️ If you like Docusaurus, give it a star on GitHub and follow us on Twitter ${TwitterSvg}`, - content: `New! Synapse Docs have been refreshed. For the previous version, click here`, }, navbar: { title: 'Synapse Docs', From 29d6bdd54b6c5b65ecec85ab5051277fa104df57 Mon Sep 17 00:00:00 2001 From: trajan0x Date: Sat, 12 Oct 2024 14:14:33 +0000 Subject: [PATCH 23/47] Publish - @synapsecns/bridge-docs@0.4.1 --- docs/bridge/CHANGELOG.md | 8 ++++++++ docs/bridge/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/bridge/CHANGELOG.md b/docs/bridge/CHANGELOG.md index 78e07f7024..5669c2dc0a 100644 --- a/docs/bridge/CHANGELOG.md +++ b/docs/bridge/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.4.1](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.4.0...@synapsecns/bridge-docs@0.4.1) (2024-10-12) + +**Note:** Version bump only for package @synapsecns/bridge-docs + + + + + # [0.4.0](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.3.11...@synapsecns/bridge-docs@0.4.0) (2024-10-10) diff --git a/docs/bridge/package.json b/docs/bridge/package.json index 2d4188f108..6f307ce757 100644 --- a/docs/bridge/package.json +++ b/docs/bridge/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/bridge-docs", - "version": "0.4.0", + "version": "0.4.1", "private": true, "scripts": { "docusaurus": "docusaurus", From d048b2cf463b0f3bce1b480cb61b757705f5e956 Mon Sep 17 00:00:00 2001 From: Moses <103143573+Defi-Moses@users.noreply.github.com> Date: Sat, 12 Oct 2024 10:21:41 -0400 Subject: [PATCH 24/47] adding search by origin tx (#3277) --- .../api/src/controllers/transactionIdController.ts | 7 ++++++- packages/rfq-indexer/api/src/routes/transactionIdRoute.ts | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/rfq-indexer/api/src/controllers/transactionIdController.ts b/packages/rfq-indexer/api/src/controllers/transactionIdController.ts index 586590220a..23f1496814 100644 --- a/packages/rfq-indexer/api/src/controllers/transactionIdController.ts +++ b/packages/rfq-indexer/api/src/controllers/transactionIdController.ts @@ -10,7 +10,12 @@ export const getTransactionById = async (req: Request, res: Response) => { try { const query = db .with('deposits', () => - qDeposits().where('transactionId', '=', transactionId as string) + qDeposits().where((eb) => + eb.or([ + eb('transactionId', '=', transactionId as string), + eb('transactionHash', '=', transactionId as string) + ]) + ) ) .with('relays', () => qRelays()) .with('proofs', () => qProofs({activeOnly: false})) // display proofs even if they have been invalidated/replaced by a dispute diff --git a/packages/rfq-indexer/api/src/routes/transactionIdRoute.ts b/packages/rfq-indexer/api/src/routes/transactionIdRoute.ts index ef0b4077a4..253060dcdf 100644 --- a/packages/rfq-indexer/api/src/routes/transactionIdRoute.ts +++ b/packages/rfq-indexer/api/src/routes/transactionIdRoute.ts @@ -8,7 +8,7 @@ const router = express.Router() * @openapi * /transaction-id/{transactionId}: * get: - * summary: Get transaction details by ID + * summary: Get transaction details by ID or the origin transaction hash * description: Retrieves detailed information about a transaction, including deposit, relay, proof, claim, and refund data if available * parameters: * - in: path @@ -16,7 +16,7 @@ const router = express.Router() * required: true * schema: * type: string - * description: The unique identifier of the transaction + * description: The unique identifier of the transaction or the origin transaction hash * responses: * 200: * description: Successful response From 6d1c35e0edb31ccbccb378750280a9251bf222b8 Mon Sep 17 00:00:00 2001 From: Defi-Moses Date: Sat, 12 Oct 2024 14:25:52 +0000 Subject: [PATCH 25/47] Publish - @synapsecns/rfq-indexer-api@1.0.7 --- packages/rfq-indexer/api/CHANGELOG.md | 8 ++++++++ packages/rfq-indexer/api/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/rfq-indexer/api/CHANGELOG.md b/packages/rfq-indexer/api/CHANGELOG.md index 3a70fb5e6e..937939a630 100644 --- a/packages/rfq-indexer/api/CHANGELOG.md +++ b/packages/rfq-indexer/api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.0.7](https://github.com/synapsecns/sanguine/compare/@synapsecns/rfq-indexer-api@1.0.6...@synapsecns/rfq-indexer-api@1.0.7) (2024-10-12) + +**Note:** Version bump only for package @synapsecns/rfq-indexer-api + + + + + ## [1.0.6](https://github.com/synapsecns/sanguine/compare/@synapsecns/rfq-indexer-api@1.0.5...@synapsecns/rfq-indexer-api@1.0.6) (2024-10-07) **Note:** Version bump only for package @synapsecns/rfq-indexer-api diff --git a/packages/rfq-indexer/api/package.json b/packages/rfq-indexer/api/package.json index e69511c2b5..9b2aa991a4 100644 --- a/packages/rfq-indexer/api/package.json +++ b/packages/rfq-indexer/api/package.json @@ -1,7 +1,7 @@ { "name": "@synapsecns/rfq-indexer-api", "private": true, - "version": "1.0.6", + "version": "1.0.7", "description": "", "main": "index.js", "scripts": { From 47562dbbf8488ba0b431136815806f2dfd0b883d Mon Sep 17 00:00:00 2001 From: trajan0x <83933037+trajan0x@users.noreply.github.com> Date: Sat, 12 Oct 2024 18:50:41 -0400 Subject: [PATCH 26/47] Fix/edit url [SLT-338] (#3279) * fix edit link [SLT-338] * fix lint issue * gtag * fix gtag --------- Co-authored-by: Trajan0x --- docs/bridge/docusaurus.config.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/bridge/docusaurus.config.ts b/docs/bridge/docusaurus.config.ts index f296f4e05a..a01aa63553 100644 --- a/docs/bridge/docusaurus.config.ts +++ b/docs/bridge/docusaurus.config.ts @@ -55,12 +55,16 @@ const config: Config = { [ 'classic', { + gtag: { + trackingID: 'G-BBC13LQXBD', + anonymizeIP: true, + }, docs: { sidebarPath: './sidebars.ts', // Please change this to your repo. // Remove this to remove the "edit this page" links. editUrl: - 'https://github.com/synapsecns/sanguine/edit/master/docs/bridge/blog-posts/', + 'https://github.com/synapsecns/sanguine/edit/master/docs/bridge/', docRootComponent: '@theme/DocRoot', docItemComponent: '@theme/ApiItem', // derived from docusaurus-theme-openapi-docs // docItemComponent: '@theme/ApiItem', // derived from docusaurus-theme-openapi-docs @@ -90,10 +94,10 @@ const config: Config = { }, // Replace with your project's social card image: 'img/docusaurus-social-card.jpg', - announcementBar: { - // id: 'announcementBar-v3.2', // Increment on change - // content: `⭐️ If you like Docusaurus, give it a star on GitHub and follow us on Twitter ${TwitterSvg}`, - }, + // announcementBar: { + // id: 'announcementBar-v3.2', // Increment on change + // content: `⭐️ If you like Docusaurus, give it a star on GitHub and follow us on Twitter ${TwitterSvg}`, + // }, navbar: { title: 'Synapse Docs', logo: { From f1dfc82bc26d60262a92feda671d44a6d54a3ce1 Mon Sep 17 00:00:00 2001 From: abtestingalpha <104046418+abtestingalpha@users.noreply.github.com> Date: Sat, 12 Oct 2024 18:53:37 -0400 Subject: [PATCH 27/47] fix(docs): Fixes gh link (#3280) * Fixes gh link * Remove empty announcement bar --------- Co-authored-by: trajan0x <83933037+trajan0x@users.noreply.github.com> --- docs/bridge/docusaurus.config.ts | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/docs/bridge/docusaurus.config.ts b/docs/bridge/docusaurus.config.ts index a01aa63553..e7fbff7146 100644 --- a/docs/bridge/docusaurus.config.ts +++ b/docs/bridge/docusaurus.config.ts @@ -95,8 +95,8 @@ const config: Config = { // Replace with your project's social card image: 'img/docusaurus-social-card.jpg', // announcementBar: { - // id: 'announcementBar-v3.2', // Increment on change - // content: `⭐️ If you like Docusaurus, give it a star on GitHub and follow us on Twitter ${TwitterSvg}`, + // id: 'announcementBar-v3.2', // Increment on change + // content: `⭐️ If you like Docusaurus, give it a star on GitHub and follow us on Twitter ${TwitterSvg}`, // }, navbar: { title: 'Synapse Docs', @@ -111,7 +111,7 @@ const config: Config = { position: 'left', label: 'Docs', }, - {to: '/blog', label: 'Blog', position: 'left'}, + { to: '/blog', label: 'Blog', position: 'left' }, { href: 'https://github.com/synapsecns/sanguine', label: 'GitHub', @@ -122,15 +122,6 @@ const config: Config = { footer: { // style: 'dark', links: [ - // { - // title: 'Docs', - // items: [ - // { - // label: 'Tutorial', - // to: '/docs/intro', - // }, - // ], - // }, { title: 'Community', items: [ @@ -153,7 +144,7 @@ const config: Config = { items: [ { label: 'GitHub', - href: 'https://github.com/facebook/docusaurus', + href: 'https://github.com/synapsecns/sanguine', }, ], }, From 70f17d3b99e8334406545a124b4a7004f4a14749 Mon Sep 17 00:00:00 2001 From: trajan0x Date: Sat, 12 Oct 2024 22:57:42 +0000 Subject: [PATCH 28/47] Publish - @synapsecns/bridge-docs@0.4.2 --- docs/bridge/CHANGELOG.md | 11 +++++++++++ docs/bridge/package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/bridge/CHANGELOG.md b/docs/bridge/CHANGELOG.md index 5669c2dc0a..d7f5871ab9 100644 --- a/docs/bridge/CHANGELOG.md +++ b/docs/bridge/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.4.2](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.4.1...@synapsecns/bridge-docs@0.4.2) (2024-10-12) + + +### Bug Fixes + +* **docs:** Fixes gh link ([#3280](https://github.com/synapsecns/sanguine/issues/3280)) ([f1dfc82](https://github.com/synapsecns/sanguine/commit/f1dfc82bc26d60262a92feda671d44a6d54a3ce1)) + + + + + ## [0.4.1](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.4.0...@synapsecns/bridge-docs@0.4.1) (2024-10-12) **Note:** Version bump only for package @synapsecns/bridge-docs diff --git a/docs/bridge/package.json b/docs/bridge/package.json index 6f307ce757..2e2d1bb267 100644 --- a/docs/bridge/package.json +++ b/docs/bridge/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/bridge-docs", - "version": "0.4.1", + "version": "0.4.2", "private": true, "scripts": { "docusaurus": "docusaurus", From 0df8f08b3617e84f1ae5d71b5e45f172e08ce2db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CF=87=C2=B2?= <88190723+ChiTimesChi@users.noreply.github.com> Date: Mon, 14 Oct 2024 10:29:51 +0100 Subject: [PATCH 29/47] feat(contracts-rfq): arbitrary call with value [SLT-233] [SLT-318] (#3246) * feat: add `callValue` to bridge params * feat: add `callValue` to bridge tx V2 * test: add cases for SRC calls with `callValue` * refactor: simplify tests further * test: add cases for DST relays with `callValue` * feat: support `callValue` in `bridge()` * feat: support `callValue` in `relay()` * test: update revert message for failed ETH transfers * refactor: always forward full msg.value for the hook call * refactor: use `_pullToken` only in `bridge()` * refactor: isolate validation of relay params * refactor: isolate validation of the bridge params * docs: could -> can * test: enable the backwards compatibility encoding test * fix: getBridgeTransaction partial support for V2 structs * test: add clarifications about expected reverts * test: more incorrect relay scenarios * refactor: better naming for `_pullToken`, docs * refactor: remove unnecessary cast * refactor: read from stack, not memory where possible * fix: emit the event prior to the external calls --- .../contracts-rfq/contracts/FastBridgeV2.sol | 259 ++++++++++-------- .../contracts/interfaces/IFastBridge.sol | 2 +- .../contracts/interfaces/IFastBridgeV2.sol | 7 +- .../interfaces/IFastBridgeV2Errors.sol | 1 + .../test/FastBridgeV2.Dst.ArbitraryCall.t.sol | 111 +++++++- .../test/FastBridgeV2.Dst.Exclusivity.t.sol | 21 +- .../contracts-rfq/test/FastBridgeV2.Dst.t.sol | 247 +++++++++++++++-- .../test/FastBridgeV2.Encoding.t.sol | 16 +- .../test/FastBridgeV2.Src.ArbitraryCall.t.sol | 53 ++++ .../contracts-rfq/test/FastBridgeV2.Src.t.sol | 2 +- .../contracts-rfq/test/FastBridgeV2.t.sol | 14 +- 11 files changed, 570 insertions(+), 163 deletions(-) diff --git a/packages/contracts-rfq/contracts/FastBridgeV2.sol b/packages/contracts-rfq/contracts/FastBridgeV2.sol index dd1d109126..b77e68a0c9 100644 --- a/packages/contracts-rfq/contracts/FastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/FastBridgeV2.sol @@ -54,6 +54,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { quoteRelayer: address(0), quoteExclusivitySeconds: 0, quoteId: bytes(""), + callValue: 0, callParams: bytes("") }) }); @@ -126,34 +127,42 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { } /// @inheritdoc IFastBridge - function getBridgeTransaction(bytes memory request) external pure returns (BridgeTransaction memory) { - // TODO: the note below isn't true anymore with the BridgeTransactionV2 struct - // since the variable length `callParams` was added. This needs to be fixed/acknowledged. - - // Note: when passing V2 request, this will decode the V1 fields correctly since the new fields were - // added as the last fields of the struct and hence the ABI decoder will simply ignore the extra data. - return abi.decode(request, (BridgeTransaction)); + /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs: + /// - `callValue` is partially reported as a zero/non-zero flag + /// - `callParams` is ignored + /// In order to process all kinds of requests use getBridgeTransactionV2 instead. + function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) { + // Try decoding into V2 struct first. This will revert if V1 struct is passed + try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) { + // Note: we entirely ignore the callParams field, as it was not present in V1 + return BridgeTransaction({ + originChainId: txV2.originChainId, + destChainId: txV2.destChainId, + originSender: txV2.originSender, + destRecipient: txV2.destRecipient, + originToken: txV2.originToken, + destToken: txV2.destToken, + originAmount: txV2.originAmount, + destAmount: txV2.destAmount, + originFeeAmount: txV2.originFeeAmount, + sendChainGas: txV2.callValue != 0, + deadline: txV2.deadline, + nonce: txV2.nonce + }); + } catch { + // Fallback to V1 struct + return abi.decode(request, (BridgeTransaction)); + } } /// @inheritdoc IFastBridgeV2 - // TODO: reduce cyclomatic complexity alongside arbitrary call - // solhint-disable-next-line code-complexity function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable { - // check bridge params - if (params.dstChainId == block.chainid) revert ChainIncorrect(); - if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect(); - if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress(); - if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress(); - if (params.deadline < block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort(); - if (paramsV2.callParams.length > MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax(); int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds; - // exclusivityEndTime must be in range (0 .. params.deadline] - if (exclusivityEndTime <= 0 || exclusivityEndTime > int256(params.deadline)) { - revert ExclusivityParamsIncorrect(); - } + _validateBridgeParams(params, paramsV2, exclusivityEndTime); + // transfer tokens to bridge contract - // @dev use returned originAmount in request in case of transfer fees - uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount); + /// @dev use returned originAmount in request in case of transfer fees + uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount); // track amount of origin token owed to protocol uint256 originFeeAmount; @@ -172,7 +181,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { originAmount: originAmount, destAmount: params.destAmount, originFeeAmount: originFeeAmount, - sendChainGas: params.sendChainGas, + callValue: paramsV2.callValue, deadline: params.deadline, nonce: senderNonces[params.sender]++, // increment nonce on every bridge exclusivityRelayer: paramsV2.quoteRelayer, @@ -184,91 +193,73 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { bytes32 transactionId = keccak256(request); bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED; - emit BridgeRequested( - transactionId, - params.sender, - request, - params.dstChainId, - params.originToken, - params.destToken, - originAmount, - params.destAmount, - params.sendChainGas - ); + emit BridgeRequested({ + transactionId: transactionId, + sender: params.sender, + request: request, + destChainId: params.dstChainId, + originToken: params.originToken, + destToken: params.destToken, + originAmount: originAmount, + destAmount: params.destAmount, + sendChainGas: paramsV2.callValue != 0 + }); emit BridgeQuoteDetails(transactionId, paramsV2.quoteId); } /// @inheritdoc IFastBridgeV2 - // TODO: reduce cyclomatic complexity alongside arbitrary call - // solhint-disable-next-line code-complexity function relay(bytes memory request, address relayer) public payable { - if (relayer == address(0)) revert ZeroAddress(); - // Check if the transaction has already been relayed bytes32 transactionId = keccak256(request); - if (bridgeRelays(transactionId)) revert TransactionRelayed(); - // Decode the transaction and check that it could be relayed on this chain BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request); - if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect(); - // Check the deadline for relay to happen - if (block.timestamp > transaction.deadline) revert DeadlineExceeded(); - // Check the exclusivity period, if it is still ongoing - // forgefmt: disable-next-item - if ( - transaction.exclusivityRelayer != address(0) && - transaction.exclusivityRelayer != relayer && - block.timestamp <= transaction.exclusivityEndTime - ) { - revert ExclusivityPeriodNotPassed(); - } + _validateRelayParams(transaction, transactionId, relayer); // mark bridge transaction as relayed bridgeRelayDetails[transactionId] = BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer}); - // transfer tokens to recipient on destination chain and gas rebate if requested + // transfer tokens to recipient on destination chain and do an arbitrary call if requested address to = transaction.destRecipient; address token = transaction.destToken; uint256 amount = transaction.destAmount; + uint256 callValue = transaction.callValue; + + // Emit the event before any external calls + emit BridgeRelayed({ + transactionId: transactionId, + relayer: relayer, + to: to, + originChainId: transaction.originChainId, + originToken: transaction.originToken, + destToken: token, + originAmount: transaction.originAmount, + destAmount: amount, + chainGasAmount: callValue + }); // All state changes have been done at this point, can proceed to the external calls. // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks. - if (transaction.callParams.length == 0) { - // No arbitrary call requested, so we just pull the tokens from the Relayer to the recipient, - // or transfer ETH to the recipient (if token is ETH_ADDRESS) - _pullToken(to, token, amount); - } else if (token != UniversalTokenLib.ETH_ADDRESS) { - // Arbitrary call requested with ERC20: pull the tokens from the Relayer to the recipient first - _pullToken(to, token, amount); - // Follow up with the hook function call - _checkedCallRecipient({ - recipient: to, - msgValue: 0, - token: token, - amount: amount, - callParams: transaction.callParams - }); + if (token == UniversalTokenLib.ETH_ADDRESS) { + // For ETH non-zero callValue is not allowed + if (callValue != 0) revert NativeTokenCallValueNotSupported(); + // Check that the correct msg.value was sent + if (msg.value != amount) revert MsgValueIncorrect(); } else { - // Arbitrary call requested with ETH: combine the ETH transfer with the call - _checkedCallRecipient({ - recipient: to, - msgValue: amount, - token: token, - amount: amount, - callParams: transaction.callParams - }); + // For ERC20s, we check that the correct msg.value was sent + if (msg.value != callValue) revert MsgValueIncorrect(); + // We need to transfer the tokens from the Relayer to the recipient first before performing an + // optional post-transfer arbitrary call. + IERC20(token).safeTransferFrom(msg.sender, to, amount); } - emit BridgeRelayed( - transactionId, - relayer, - to, - transaction.originChainId, - transaction.originToken, - transaction.destToken, - transaction.originAmount, - transaction.destAmount, - // chainGasAmount is 0 since the gas rebate function is deprecated - 0 - ); + if (transaction.callParams.length != 0) { + // Arbitrary call requested, perform it while supplying full msg.value to the recipient + // Note: if token has a fee on transfers, the recipient will have received less than `amount`. + // This is a very niche edge case and should be handled by the recipient contract. + _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams}); + } else if (msg.value != 0) { + // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH, + // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient. + Address.sendValue(payable(to), msg.value); + } } /// @inheritdoc IFastBridgeV2 @@ -335,26 +326,24 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { return abi.decode(request, (BridgeTransactionV2)); } - /// @notice Pulls a requested token from the user to the requested recipient. - /// @dev Be careful of re-entrancy issues when msg.value > 0 and recipient != address(this) - function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) { - if (token != UniversalTokenLib.ETH_ADDRESS) { + /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later + /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user, + /// should no one complete the relay. + function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) { + if (token == UniversalTokenLib.ETH_ADDRESS) { + // For ETH we just need to check that the supplied msg.value is correct. + // Supplied `msg.value` is already in FastBridgeV2 custody. + if (amount != msg.value) revert MsgValueIncorrect(); + amountTaken = msg.value; + } else { + // For ERC20s, token is explicitly transferred from the user to FastBridgeV2. + // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2. token.assertIsContract(); - // Token needs to be pulled only if msg.value is zero - // This way user can specify WETH as the origin asset if (msg.value != 0) revert MsgValueIncorrect(); - // Record token balance before transfer - amountPulled = IERC20(token).balanceOf(recipient); - IERC20(token).safeTransferFrom(msg.sender, recipient, amount); - // Use the difference between the recorded balance and the current balance as the amountPulled - amountPulled = IERC20(token).balanceOf(recipient) - amountPulled; - } else { - // Otherwise, we need to check that ETH amount matches msg.value - if (amount != msg.value) revert MsgValueIncorrect(); - // Transfer value to recipient if not this address - if (recipient != address(this)) token.universalTransfer(recipient, amount); - // We will forward msg.value in the external call later, if recipient is not this contract - amountPulled = msg.value; + amountTaken = IERC20(token).balanceOf(address(this)); + IERC20(token).safeTransferFrom(msg.sender, address(this), amount); + // Use the balance difference as the amount taken in case of fee on transfer tokens. + amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken; } } @@ -362,7 +351,6 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { /// all the necessary checks for the returned value. function _checkedCallRecipient( address recipient, - uint256 msgValue, address token, uint256 amount, bytes memory callParams @@ -372,7 +360,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { bytes memory hookData = abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams)); // This will bubble any revert messages from the hook function - bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msgValue}); + bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value}); // Explicit revert if no return data at all if (returnData.length == 0) revert RecipientNoReturnValue(); // Check that exactly a single return value was returned @@ -394,4 +382,59 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { delta = uint40(block.timestamp) - proofBlockTimestamp; } } + + /// @notice Performs all the necessary checks for a bridge to happen. + /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to + /// the number of checks that need to be performed, so we skip the code-complexity rule here. + // solhint-disable-next-line code-complexity + function _validateBridgeParams( + BridgeParams memory params, + BridgeParamsV2 memory paramsV2, + int256 exclusivityEndTime + ) + internal + view + { + // Check V1 (legacy) params + if (params.dstChainId == block.chainid) revert ChainIncorrect(); + if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect(); + if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress(); + if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress(); + if (params.deadline < block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort(); + // Check V2 params + if (paramsV2.callParams.length > MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax(); + if (paramsV2.callValue != 0 && params.destToken == UniversalTokenLib.ETH_ADDRESS) { + revert NativeTokenCallValueNotSupported(); + } + // exclusivityEndTime must be in range (0 .. params.deadline] + if (exclusivityEndTime <= 0 || exclusivityEndTime > int256(params.deadline)) { + revert ExclusivityParamsIncorrect(); + } + } + + /// @notice Performs all the necessary checks for a relay to happen. + function _validateRelayParams( + BridgeTransactionV2 memory transaction, + bytes32 transactionId, + address relayer + ) + internal + view + { + if (relayer == address(0)) revert ZeroAddress(); + // Check if the transaction has already been relayed + if (bridgeRelays(transactionId)) revert TransactionRelayed(); + if (transaction.destChainId != block.chainid) revert ChainIncorrect(); + // Check the deadline for relay to happen + if (block.timestamp > transaction.deadline) revert DeadlineExceeded(); + // Check the exclusivity period, if it is still ongoing + // forgefmt: disable-next-item + if ( + transaction.exclusivityRelayer != address(0) && + transaction.exclusivityRelayer != relayer && + block.timestamp <= transaction.exclusivityEndTime + ) { + revert ExclusivityPeriodNotPassed(); + } + } } diff --git a/packages/contracts-rfq/contracts/interfaces/IFastBridge.sol b/packages/contracts-rfq/contracts/interfaces/IFastBridge.sol index b691dfb5b4..033d602f76 100644 --- a/packages/contracts-rfq/contracts/interfaces/IFastBridge.sol +++ b/packages/contracts-rfq/contracts/interfaces/IFastBridge.sol @@ -97,7 +97,7 @@ interface IFastBridge { /// @notice Decodes bridge request into a bridge transaction /// @param request The bridge request to decode - function getBridgeTransaction(bytes memory request) external pure returns (BridgeTransaction memory); + function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory); /// @notice Checks if the dispute period has passed so bridge deposit can be claimed /// @param transactionId The transaction id associated with the encoded bridge transaction to check diff --git a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol index c4c3751a5b..54dbb5f3f6 100644 --- a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol @@ -30,14 +30,17 @@ interface IFastBridgeV2 is IFastBridge { /// for backwards compatibility. /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity) /// or both non-zero (indicating exclusivity for the given period). + /// Note: callValue > 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS) /// @param quoteRelayer Relayer that provided the quote for the transaction /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit /// @param quoteId Unique quote identifier used for tracking the quote + /// @param callValue ETH value to send to the recipient (if any) /// @param callParams Parameters for the arbitrary call to the destination recipient (if any) struct BridgeParamsV2 { address quoteRelayer; int256 quoteExclusivitySeconds; bytes quoteId; + uint256 callValue; bytes callParams; } @@ -54,7 +57,7 @@ interface IFastBridgeV2 is IFastBridge { uint256 originAmount; // amount in on origin bridge less originFeeAmount uint256 destAmount; uint256 originFeeAmount; - bool sendChainGas; + uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag uint256 deadline; // user specified deadline for destination relay uint256 nonce; address exclusivityRelayer; @@ -67,7 +70,7 @@ interface IFastBridgeV2 is IFastBridge { /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability /// to provide temporary exclusivity fill rights for the quote relayer. /// @param params The parameters required to bridge - /// @param paramsV2 The parameters for exclusivity fill rights (optional, could be left empty) + /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty) function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable; /// @notice Relays destination side of bridge transaction by off-chain relayer diff --git a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2Errors.sol b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2Errors.sol index 7cc1423a84..f40b760c30 100644 --- a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2Errors.sol +++ b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2Errors.sol @@ -7,6 +7,7 @@ interface IFastBridgeV2Errors { error ChainIncorrect(); error ExclusivityParamsIncorrect(); error MsgValueIncorrect(); + error NativeTokenCallValueNotSupported(); error SenderIncorrect(); error StatusIncorrect(); error ZeroAddress(); diff --git a/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol index af4f6235c6..1fb3ed8148 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {FastBridgeV2DstExclusivityTest, IFastBridgeV2} from "./FastBridgeV2.Dst.Exclusivity.t.sol"; +import {IFastBridgeV2} from "../contracts/interfaces/IFastBridgeV2.sol"; +import {FastBridgeV2DstExclusivityTest} from "./FastBridgeV2.Dst.Exclusivity.t.sol"; import {RecipientMock} from "./mocks/RecipientMock.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; @@ -98,6 +99,28 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } + function test_relay_token_withCallValue_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(excessiveReturnValueRecipient); + vm.expectRevert(RecipientIncorrectReturnValue.selector); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(excessiveReturnValueRecipient); + vm.expectRevert(RecipientIncorrectReturnValue.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + function test_relay_eth_excessiveReturnValueRecipient_revertWhenCallParamsPresent() public virtual override { setEthTestRecipient(excessiveReturnValueRecipient); vm.expectRevert(RecipientIncorrectReturnValue.selector); @@ -132,6 +155,28 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } + function test_relay_token_withCallValue_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(incorrectReturnValueRecipient); + vm.expectRevert(RecipientIncorrectReturnValue.selector); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(incorrectReturnValueRecipient); + vm.expectRevert(RecipientIncorrectReturnValue.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + function test_relay_eth_incorrectReturnValueRecipient_revertWhenCallParamsPresent() public virtual override { setEthTestRecipient(incorrectReturnValueRecipient); vm.expectRevert(RecipientIncorrectReturnValue.selector); @@ -150,6 +195,8 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { // ══════════════════════════════════════════════ NO-OP RECIPIENT ══════════════════════════════════════════════════ + // Note: in these tests NoOpRecipient doesn't implement hook function, so we expect a generic OZ library revert. + function test_relay_token_noOpRecipient_revertWhenCallParamsPresent() public virtual override { setTokenTestRecipient(noOpRecipient); vm.expectRevert(Address.FailedInnerCall.selector); @@ -162,6 +209,24 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } + function test_relay_token_withCallValue_noOpRecipient_revertWhenCallParamsPresent() public virtual override { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noOpRecipient); + vm.expectRevert(Address.FailedInnerCall.selector); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_noOpRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noOpRecipient); + vm.expectRevert(Address.FailedInnerCall.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + function test_relay_eth_noOpRecipient_revertWhenCallParamsPresent() public virtual override { setEthTestRecipient(noOpRecipient); vm.expectRevert(Address.FailedInnerCall.selector); @@ -192,6 +257,28 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } + function test_relay_token_withCallValue_noReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noReturnValueRecipient); + vm.expectRevert(RecipientNoReturnValue.selector); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_noReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noReturnValueRecipient); + vm.expectRevert(RecipientNoReturnValue.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + function test_relay_eth_noReturnValueRecipient_revertWhenCallParamsPresent() public virtual override { setEthTestRecipient(noReturnValueRecipient); vm.expectRevert(RecipientNoReturnValue.selector); @@ -222,6 +309,20 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } + function test_relay_token_withCallValue_revert_recipientReverts() public { + setTokenTestCallValue(CALL_VALUE); + mockRecipientRevert(tokenTx); + vm.expectRevert(REVERT_MSG); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_revert_recipientReverts() public { + setTokenTestCallValue(CALL_VALUE); + mockRecipientRevert(tokenTx); + vm.expectRevert(REVERT_MSG); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + function test_relay_eth_revert_recipientReverts() public { mockRecipientRevert(ethTx); vm.expectRevert(REVERT_MSG); @@ -237,14 +338,18 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { function test_relay_eth_noCallParams_revert_recipientReverts() public { setEthTestCallParams(""); vm.mockCallRevert({callee: userB, data: "", revertData: bytes(REVERT_MSG)}); - vm.expectRevert("ETH transfer failed"); + // Note: OZ library doesn't bubble the revert message for just sending ETH + // (as opposed to doing an external hook call). Therefore we expect a generic library revert. + vm.expectRevert(Address.FailedInnerCall.selector); relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); } function test_relay_eth_withRelayerAddress_noCallParams_revert_recipientReverts() public { setEthTestCallParams(""); vm.mockCallRevert({callee: userB, data: "", revertData: bytes(REVERT_MSG)}); - vm.expectRevert("ETH transfer failed"); + // Note: OZ library doesn't bubble the revert message for just sending ETH + // (as opposed to doing an external hook call). Therefore we expect a generic library revert. + vm.expectRevert(Address.FailedInnerCall.selector); relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); } } diff --git a/packages/contracts-rfq/test/FastBridgeV2.Dst.Exclusivity.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Dst.Exclusivity.t.sol index a616872f93..ba66ae53c4 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Dst.Exclusivity.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Dst.Exclusivity.t.sol @@ -1,30 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {FastBridgeV2DstTest, IFastBridgeV2} from "./FastBridgeV2.Dst.t.sol"; +import {FastBridgeV2DstTest} from "./FastBridgeV2.Dst.t.sol"; // solhint-disable func-name-mixedcase, ordering contract FastBridgeV2DstExclusivityTest is FastBridgeV2DstTest { uint256 public constant EXCLUSIVITY_PERIOD = 60 seconds; function createFixturesV2() public virtual override { - tokenParamsV2 = IFastBridgeV2.BridgeParamsV2({ - quoteRelayer: relayerA, - quoteExclusivitySeconds: int256(EXCLUSIVITY_PERIOD), - quoteId: "", - callParams: "" - }); - ethParamsV2 = IFastBridgeV2.BridgeParamsV2({ - quoteRelayer: relayerB, - quoteExclusivitySeconds: int256(EXCLUSIVITY_PERIOD), - quoteId: "", - callParams: "" - }); - - tokenTx.exclusivityRelayer = relayerA; - tokenTx.exclusivityEndTime = block.timestamp + EXCLUSIVITY_PERIOD; - ethTx.exclusivityRelayer = relayerB; - ethTx.exclusivityEndTime = block.timestamp + EXCLUSIVITY_PERIOD; + setTokenTestExclusivityParams(relayerA, EXCLUSIVITY_PERIOD); + setEthTestExclusivityParams(relayerB, EXCLUSIVITY_PERIOD); } // ═══════════════════════════════════════════════ RELAY: TOKEN ════════════════════════════════════════════════════ diff --git a/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol index 026fed12f9..047ad6bec2 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol @@ -23,6 +23,8 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { uint256 chainGasAmount ); + uint256 public constant CALL_VALUE = 1_337_420; + address public excessiveReturnValueRecipient; address public incorrectReturnValueRecipient; address public noOpRecipient; @@ -67,6 +69,7 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { public virtual { + uint256 chainGasAmount = bridgeTx.destToken == ETH_ADDRESS ? 0 : bridgeTx.callValue; vm.expectEmit(address(fastBridge)); emit BridgeRelayed({ transactionId: txId, @@ -77,7 +80,7 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { destToken: bridgeTx.destToken, originAmount: bridgeTx.originAmount, destAmount: bridgeTx.destAmount, - chainGasAmount: 0 + chainGasAmount: chainGasAmount }); } @@ -89,15 +92,25 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { assertEq(relayer, expectedRelayer); } + function checkTokenBalances(address recipient, address relayCaller) public view { + assertEq(dstToken.balanceOf(recipient), tokenParams.destAmount); + assertEq(dstToken.balanceOf(relayCaller), LEFTOVER_BALANCE); + assertEq(dstToken.balanceOf(address(fastBridge)), 0); + } + + function checkEthBalances(address recipient, address relayCaller) public view { + assertEq(recipient.balance, ethParams.destAmount); + assertEq(relayCaller.balance, LEFTOVER_BALANCE); + assertEq(address(fastBridge).balance, 0); + } + /// @notice RelayerA completes the ERC20 bridge request function test_relay_token() public { bytes32 txId = getTxId(tokenTx); expectBridgeRelayed(tokenTx, txId, relayerA); relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx}); checkRelayedViews({txId: txId, expectedRelayer: relayerA}); - assertEq(dstToken.balanceOf(userB), tokenParams.destAmount); - assertEq(dstToken.balanceOf(relayerA), LEFTOVER_BALANCE); - assertEq(dstToken.balanceOf(address(fastBridge)), 0); + checkTokenBalances({recipient: userB, relayCaller: relayerA}); } /// @notice RelayerB completes the ERC20 bridge request, using relayerA's address @@ -106,9 +119,7 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { expectBridgeRelayed(tokenTx, txId, relayerA); relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); checkRelayedViews({txId: txId, expectedRelayer: relayerA}); - assertEq(dstToken.balanceOf(userB), tokenParams.destAmount); - assertEq(dstToken.balanceOf(relayerB), LEFTOVER_BALANCE); - assertEq(dstToken.balanceOf(address(fastBridge)), 0); + checkTokenBalances({recipient: userB, relayCaller: relayerB}); } /// @notice RelayerB completes the ETH bridge request @@ -117,9 +128,7 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { expectBridgeRelayed(ethTx, txId, relayerB); relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); checkRelayedViews({txId: txId, expectedRelayer: relayerB}); - assertEq(userB.balance, ethParams.destAmount); - assertEq(relayerB.balance, LEFTOVER_BALANCE); - assertEq(address(fastBridge).balance, 0); + checkEthBalances({recipient: userB, relayCaller: relayerB}); } /// @notice RelayerA completes the ETH bridge request, using relayerB's address @@ -128,9 +137,7 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { expectBridgeRelayed(ethTx, txId, relayerB); relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); checkRelayedViews({txId: txId, expectedRelayer: relayerB}); - assertEq(userB.balance, ethParams.destAmount); - assertEq(relayerA.balance, LEFTOVER_BALANCE); - assertEq(address(fastBridge).balance, 0); + checkEthBalances({recipient: userB, relayCaller: relayerA}); } /// @notice RelayerA completes the ETH bridge request, using relayerB's address @@ -146,9 +153,29 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { assertEq(recordedBlockNumber, 987_654_321); assertEq(recordedBlockTimestamp, 123_456_789); assertEq(recordedRelayer, relayerB); - assertEq(userB.balance, ethParams.destAmount); - assertEq(relayerA.balance, LEFTOVER_BALANCE); - assertEq(address(fastBridge).balance, 0); + checkEthBalances({recipient: userB, relayCaller: relayerA}); + } + + // ══════════════════════════════════════════ RELAYS WITH CALL VALUE ═══════════════════════════════════════════════ + + function test_relay_token_withCallValue() public { + setTokenTestCallValue(CALL_VALUE); + bytes32 txId = getTxId(tokenTx); + expectBridgeRelayed(tokenTx, txId, relayerA); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + checkRelayedViews({txId: txId, expectedRelayer: relayerA}); + checkTokenBalances({recipient: userB, relayCaller: relayerA}); + assertEq(userB.balance, CALL_VALUE); + } + + function test_relay_token_withRelayerAddressCallValue() public { + setTokenTestCallValue(CALL_VALUE); + bytes32 txId = getTxId(tokenTx); + expectBridgeRelayed(tokenTx, txId, relayerA); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + checkRelayedViews({txId: txId, expectedRelayer: relayerA}); + checkTokenBalances({recipient: userB, relayCaller: relayerB}); + assertEq(userB.balance, CALL_VALUE); } // ═════════════════════════════════════ EXCESSIVE RETURN VALUE RECIPIENT ══════════════════════════════════════════ @@ -171,6 +198,26 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { test_relay_token_withRelayerAddress(); } + function test_relay_token_withCallValue_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(excessiveReturnValueRecipient); + test_relay_token_withCallValue(); + } + + function test_relay_token_withRelayerAddressCallValue_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(excessiveReturnValueRecipient); + test_relay_token_withRelayerAddressCallValue(); + } + function test_relay_eth_excessiveReturnValueRecipient_revertWhenCallParamsPresent() public virtual { assertEmptyCallParams(ethTx.callParams); setEthTestRecipient(excessiveReturnValueRecipient); @@ -206,6 +253,26 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { test_relay_token_withRelayerAddress(); } + function test_relay_token_withCallValue_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(incorrectReturnValueRecipient); + test_relay_token_withCallValue(); + } + + function test_relay_token_withRelayerAddressCallValue_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(incorrectReturnValueRecipient); + test_relay_token_withRelayerAddressCallValue(); + } + function test_relay_eth_incorrectReturnValueRecipient_revertWhenCallParamsPresent() public virtual { assertEmptyCallParams(ethTx.callParams); setEthTestRecipient(incorrectReturnValueRecipient); @@ -234,6 +301,20 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { test_relay_token_withRelayerAddress(); } + function test_relay_token_withCallValue_nonPayableRecipient_revert() public { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(nonPayableRecipient); + vm.expectRevert(); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_nonPayableRecipient_revert() public { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(nonPayableRecipient); + vm.expectRevert(); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + function test_relay_eth_revert_nonPayableRecipient() public { setEthTestRecipient(nonPayableRecipient); vm.expectRevert(); @@ -263,6 +344,20 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { test_relay_token_withRelayerAddress(); } + function test_relay_token_withCallValue_noOpRecipient_revertWhenCallParamsPresent() public virtual { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noOpRecipient); + test_relay_token_withCallValue(); + } + + function test_relay_token_withRelayerAddressCallValue_noOpRecipient_revertWhenCallParamsPresent() public virtual { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noOpRecipient); + test_relay_token_withRelayerAddressCallValue(); + } + function test_relay_eth_noOpRecipient_revertWhenCallParamsPresent() public virtual { assertEmptyCallParams(ethTx.callParams); setEthTestRecipient(noOpRecipient); @@ -292,6 +387,23 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { test_relay_token_withRelayerAddress(); } + function test_relay_token_withCallValue_noReturnValueRecipient_revertWhenCallParamsPresent() public virtual { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noReturnValueRecipient); + test_relay_token_withCallValue(); + } + + function test_relay_token_withRelayerAddressCallValue_noReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noReturnValueRecipient); + test_relay_token_withRelayerAddressCallValue(); + } + function test_relay_eth_noReturnValueRecipient_revertWhenCallParamsPresent() public virtual { assertEmptyCallParams(ethTx.callParams); setEthTestRecipient(noReturnValueRecipient); @@ -361,6 +473,69 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { relayWithAddress({caller: relayerA, relayer: address(0), msgValue: 0, bridgeTx: tokenTx}); } + function test_relay_token_withCallValue_revert_zeroCallValue() public { + setTokenTestCallValue(CALL_VALUE); + vm.expectRevert(MsgValueIncorrect.selector); + relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx}); + } + + function test_relay_token_withCallValue_revert_lowerCallValue() public { + setTokenTestCallValue(CALL_VALUE); + vm.expectRevert(MsgValueIncorrect.selector); + relay({caller: relayerA, msgValue: CALL_VALUE - 1, bridgeTx: tokenTx}); + } + + function test_relay_token_withCallValue_revert_higherCallValue() public { + setTokenTestCallValue(CALL_VALUE); + vm.expectRevert(MsgValueIncorrect.selector); + relay({caller: relayerA, msgValue: CALL_VALUE + 1, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_revert_zeroCallValue() public { + setTokenTestCallValue(CALL_VALUE); + vm.expectRevert(MsgValueIncorrect.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_revert_lowerCallValue() public { + setTokenTestCallValue(CALL_VALUE); + vm.expectRevert(MsgValueIncorrect.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE - 1, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_revert_higherCallValue() public { + setTokenTestCallValue(CALL_VALUE); + vm.expectRevert(MsgValueIncorrect.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE + 1, bridgeTx: tokenTx}); + } + + function test_relay_eth_withCallValue_revert_notSupported() public { + setEthTestCallValue(CALL_VALUE); + // Neither destAmount, CALL_VALUE, nor destAmount + CALL_VALUE should work here + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + relay({caller: relayerB, msgValue: CALL_VALUE, bridgeTx: ethTx}); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + relay({caller: relayerB, msgValue: ethParams.destAmount + CALL_VALUE, bridgeTx: ethTx}); + } + + function test_relay_eth_withRelayerAddressCallValue_revert_notSupported() public { + setEthTestCallValue(CALL_VALUE); + // Neither destAmount, CALL_VALUE, nor destAmount + CALL_VALUE should work here + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: CALL_VALUE, bridgeTx: ethTx}); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + relayWithAddress({ + caller: relayerA, + relayer: relayerB, + msgValue: ethParams.destAmount + CALL_VALUE, + bridgeTx: ethTx + }); + } + function test_relay_token_revert_approvedZero() public { vm.prank(relayerA); dstToken.approve(address(fastBridge), 0); @@ -380,18 +555,52 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { relay({caller: relayerA, msgValue: tokenParams.destAmount, bridgeTx: tokenTx}); } + function test_relay_token_withRelayerAddress_revert_approvedZero() public { + vm.prank(relayerB); + dstToken.approve(address(fastBridge), 0); + vm.expectRevert(); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddress_revert_approvedNotEnough() public { + vm.prank(relayerB); + dstToken.approve(address(fastBridge), tokenParams.destAmount - 1); + vm.expectRevert(); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddress_revert_nonZeroMsgValue() public { + vm.expectRevert(); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: tokenParams.destAmount, bridgeTx: tokenTx}); + } + function test_relay_eth_revert_lowerMsgValue() public { vm.expectRevert(); - relay({caller: relayerA, msgValue: ethParams.destAmount - 1, bridgeTx: ethTx}); + relay({caller: relayerB, msgValue: ethParams.destAmount - 1, bridgeTx: ethTx}); } function test_relay_eth_revert_higherMsgValue() public { vm.expectRevert(); - relay({caller: relayerA, msgValue: ethParams.destAmount + 1, bridgeTx: ethTx}); + relay({caller: relayerB, msgValue: ethParams.destAmount + 1, bridgeTx: ethTx}); } function test_relay_eth_revert_zeroMsgValue() public { vm.expectRevert(); - relay({caller: relayerA, msgValue: 0, bridgeTx: ethTx}); + relay({caller: relayerB, msgValue: 0, bridgeTx: ethTx}); + } + + function test_relay_eth_withRelayerAddress_revert_lowerMsgValue() public { + vm.expectRevert(); + relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount - 1, bridgeTx: ethTx}); + } + + function test_relay_eth_withRelayerAddress_revert_higherMsgValue() public { + vm.expectRevert(); + relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount + 1, bridgeTx: ethTx}); + } + + function test_relay_eth_withRelayerAddress_revert_zeroMsgValue() public { + vm.expectRevert(); + relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: 0, bridgeTx: ethTx}); } } diff --git a/packages/contracts-rfq/test/FastBridgeV2.Encoding.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Encoding.t.sol index 0918c66bf5..21d32876fc 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Encoding.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Encoding.t.sol @@ -47,17 +47,15 @@ contract FastBridgeV2EncodingTest is FastBridgeV2Test { assertEq(decodedTx, bridgeTx); } - // The addition of variable length field (callParams) in BridgeTransactionV2 breaks the compatibility - // with the original BridgeTransaction struct. - // Solidity's abi.encode(bridgeTxV2) will use the first 32 bytes to encode the data offset for the whole struct, - // which is ALWAYS equal to 32 (data starts right after the offset). This is weird, but it is what it is. - // https://ethereum.stackexchange.com/questions/152971/abi-encode-decode-mystery-additional-32-byte-field-uniswap-v2 - function test_getBridgeTransaction_supportsV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTxV2) public { - // TODO: reevaluate the necessity of this test if/when the encoding scheme is changed - vm.skip(true); + /// @notice We expect all the V1 fields except for `sendChainGas` to match. + /// `sendChainGas` is replaced with `callValue` in V2, therefore we expect non-zero `callValue` + /// to match `sendChainGas = true` in V1 + function test_getBridgeTransaction_supportsV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTxV2) public view { bytes memory request = abi.encode(bridgeTxV2); IFastBridge.BridgeTransaction memory decodedTx = fastBridge.getBridgeTransaction(request); - assertEq(decodedTx, extractV1(bridgeTxV2)); + IFastBridge.BridgeTransaction memory expectedTx = extractV1(bridgeTxV2); + expectedTx.sendChainGas = bridgeTxV2.callValue > 0; + assertEq(decodedTx, expectedTx); } function test_getBridgeTransactionV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTxV2) public view { diff --git a/packages/contracts-rfq/test/FastBridgeV2.Src.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Src.ArbitraryCall.t.sol index 2b1e83a30c..5b6e84b732 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Src.ArbitraryCall.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Src.ArbitraryCall.t.sol @@ -6,6 +6,7 @@ import {FastBridgeV2SrcExclusivityTest} from "./FastBridgeV2.Src.Exclusivity.t.s // solhint-disable func-name-mixedcase, ordering contract FastBridgeV2SrcArbitraryCallTest is FastBridgeV2SrcExclusivityTest { bytes public constant CALL_PARAMS = abi.encode("Hello, World!"); + uint256 public constant CALL_VALUE = 1_337_420; function createFixturesV2() public virtual override { super.createFixturesV2(); @@ -41,4 +42,56 @@ contract FastBridgeV2SrcArbitraryCallTest is FastBridgeV2SrcExclusivityTest { vm.expectRevert(CallParamsLengthAboveMax.selector); bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); } + + // ══════════════════════════════════════ WITH CALL VALUE, NO CALL PARAMS ══════════════════════════════════════════ + + function test_bridge_token_withCallValue_noCallParams() public { + setTokenTestCallParams(""); + setTokenTestCallValue(CALL_VALUE); + test_bridge_token(); + } + + function test_bridge_token_diffSender_withCallValue_noCallParams() public { + setTokenTestCallParams(""); + setTokenTestCallValue(CALL_VALUE); + test_bridge_token_diffSender(); + } + + function test_bridge_eth_withCallValue_noCallParams_revert() public { + setEthTestCallParams(""); + setEthTestCallValue(CALL_VALUE); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + } + + function test_bridge_eth_diffSender_withCallValue_noCallParams_revert() public { + setEthTestCallParams(""); + setEthTestCallValue(CALL_VALUE); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + bridge({caller: userB, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + } + + // ═══════════════════════════════════════ WITH CALL VALUE & CALL PARAMS ═══════════════════════════════════════════ + + function test_bridge_token_withCallValue_withCallParams() public { + setTokenTestCallValue(CALL_VALUE); + test_bridge_token(); + } + + function test_bridge_token_diffSender_withCallValue_withCallParams() public { + setTokenTestCallValue(CALL_VALUE); + test_bridge_token_diffSender(); + } + + function test_bridge_eth_withCallValue_withCallParams_revert() public { + setEthTestCallValue(CALL_VALUE); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + } + + function test_bridge_eth_diffSender_withCallValue_withCallParams_revert() public { + setEthTestCallValue(CALL_VALUE); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + bridge({caller: userB, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + } } diff --git a/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol index 3a9edd328c..5baa42bda0 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol @@ -42,7 +42,7 @@ contract FastBridgeV2SrcTest is FastBridgeV2SrcBaseTest { destToken: bridgeTx.destToken, originAmount: bridgeTx.originAmount, destAmount: bridgeTx.destAmount, - sendChainGas: bridgeTx.sendChainGas + sendChainGas: bridgeTx.callValue > 0 }); } diff --git a/packages/contracts-rfq/test/FastBridgeV2.t.sol b/packages/contracts-rfq/test/FastBridgeV2.t.sol index e195d8fabf..fca2bad7c3 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.t.sol @@ -128,12 +128,14 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { quoteRelayer: address(0), quoteExclusivitySeconds: 0, quoteId: bytes(""), + callValue: 0, callParams: bytes("") }); ethParamsV2 = IFastBridgeV2.BridgeParamsV2({ quoteRelayer: address(0), quoteExclusivitySeconds: 0, quoteId: bytes(""), + callValue: 0, callParams: bytes("") }); @@ -158,7 +160,6 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { txV2.originAmount = txV1.originAmount; txV2.destAmount = txV1.destAmount; txV2.originFeeAmount = txV1.originFeeAmount; - txV2.sendChainGas = txV1.sendChainGas; txV2.deadline = txV1.deadline; txV2.nonce = txV1.nonce; } @@ -168,6 +169,11 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { tokenTx.callParams = callParams; } + function setTokenTestCallValue(uint256 callValue) public { + tokenParamsV2.callValue = callValue; + tokenTx.callValue = callValue; + } + function setTokenTestExclusivityParams(address relayer, uint256 exclusivitySeconds) public { tokenParamsV2.quoteRelayer = relayer; tokenParamsV2.quoteExclusivitySeconds = int256(exclusivitySeconds); @@ -182,6 +188,11 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { ethTx.callParams = callParams; } + function setEthTestCallValue(uint256 callValue) public { + ethParamsV2.callValue = callValue; + ethTx.callValue = callValue; + } + function setEthTestExclusivityParams(address relayer, uint256 exclusivitySeconds) public { ethParamsV2.quoteRelayer = relayer; ethParamsV2.quoteExclusivitySeconds = int256(exclusivitySeconds); @@ -205,7 +216,6 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { txV1.originAmount = txV2.originAmount; txV1.destAmount = txV2.destAmount; txV1.originFeeAmount = txV2.originFeeAmount; - txV1.sendChainGas = txV2.sendChainGas; txV1.deadline = txV2.deadline; txV1.nonce = txV2.nonce; } From bc21cfa85a8b0044bb70af787ee3fd1dd2b62f75 Mon Sep 17 00:00:00 2001 From: ChiTimesChi Date: Mon, 14 Oct 2024 09:34:08 +0000 Subject: [PATCH 30/47] Publish - @synapsecns/contracts-rfq@0.8.0 --- packages/contracts-rfq/CHANGELOG.md | 11 +++++++++++ packages/contracts-rfq/package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/contracts-rfq/CHANGELOG.md b/packages/contracts-rfq/CHANGELOG.md index de399bd2ae..470170f018 100644 --- a/packages/contracts-rfq/CHANGELOG.md +++ b/packages/contracts-rfq/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [0.8.0](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.7.3...@synapsecns/contracts-rfq@0.8.0) (2024-10-14) + + +### Features + +* **contracts-rfq:** arbitrary call with value [SLT-233] [SLT-318] ([#3246](https://github.com/synapsecns/sanguine/issues/3246)) ([0df8f08](https://github.com/synapsecns/sanguine/commit/0df8f08b3617e84f1ae5d71b5e45f172e08ce2db)) + + + + + ## [0.7.3](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.7.2...@synapsecns/contracts-rfq@0.7.3) (2024-10-11) **Note:** Version bump only for package @synapsecns/contracts-rfq diff --git a/packages/contracts-rfq/package.json b/packages/contracts-rfq/package.json index dc5bd9c504..09d3dd387e 100644 --- a/packages/contracts-rfq/package.json +++ b/packages/contracts-rfq/package.json @@ -1,7 +1,7 @@ { "name": "@synapsecns/contracts-rfq", "license": "MIT", - "version": "0.7.3", + "version": "0.8.0", "description": "FastBridge contracts.", "private": true, "files": [ From de92c1f24d8c5d08bd87ab03a203a1bdc8225000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CF=87=C2=B2?= <88190723+ChiTimesChi@users.noreply.github.com> Date: Mon, 14 Oct 2024 11:20:53 +0100 Subject: [PATCH 31/47] chore(contracts-rfq): gas bench script (#3283) * chore: add gas:bench script * ci: use the defined script --- .github/workflows/solidity.yml | 4 +++- packages/contracts-rfq/package.json | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/solidity.yml b/.github/workflows/solidity.yml index 9e8c807f31..3d41291c8b 100644 --- a/.github/workflows/solidity.yml +++ b/.github/workflows/solidity.yml @@ -267,7 +267,9 @@ jobs: - name: Run tests and generate gas report working-directory: './packages/${{matrix.package}}' # Run separate set of tests (no fuzzing) to get accurate average gas cost estimates - run: forge test --mc GasBenchmark --gas-report > "../../gas-report-${{ matrix.package }}.ansi" + # Note: we use `npm run` with `--if-present` flag, allows not to define a gas:bench script in every package + # This is not natively supported by yarn yet, see: https://github.com/yarnpkg/yarn/pull/7159 + run: npm run gas:bench --if-present > "../../gas-report-${{ matrix.package }}.ansi" - name: Compare gas reports uses: Rubilmax/foundry-gas-diff@v3.18 diff --git a/packages/contracts-rfq/package.json b/packages/contracts-rfq/package.json index 09d3dd387e..715fcf5152 100644 --- a/packages/contracts-rfq/package.json +++ b/packages/contracts-rfq/package.json @@ -20,6 +20,7 @@ "build:slither": "forge build --out=out --build-info --force", "test:coverage": "echo 'Please use foundry'", "test": "forge test", + "gas:bench": "forge test --mc GasBenchmark --gas-report", "lint": "forge fmt && npm run solhint", "lint:check": "forge fmt --check && npm run solhint:check", "ci:lint": "npm run lint:check", From 3bad56c17683784a007081f49f895b33490a71c2 Mon Sep 17 00:00:00 2001 From: ChiTimesChi Date: Mon, 14 Oct 2024 10:25:01 +0000 Subject: [PATCH 32/47] Publish - @synapsecns/contracts-rfq@0.8.1 --- packages/contracts-rfq/CHANGELOG.md | 8 ++++++++ packages/contracts-rfq/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/contracts-rfq/CHANGELOG.md b/packages/contracts-rfq/CHANGELOG.md index 470170f018..2cdda57ace 100644 --- a/packages/contracts-rfq/CHANGELOG.md +++ b/packages/contracts-rfq/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.8.1](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.8.0...@synapsecns/contracts-rfq@0.8.1) (2024-10-14) + +**Note:** Version bump only for package @synapsecns/contracts-rfq + + + + + # [0.8.0](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.7.3...@synapsecns/contracts-rfq@0.8.0) (2024-10-14) diff --git a/packages/contracts-rfq/package.json b/packages/contracts-rfq/package.json index 715fcf5152..45f09710e3 100644 --- a/packages/contracts-rfq/package.json +++ b/packages/contracts-rfq/package.json @@ -1,7 +1,7 @@ { "name": "@synapsecns/contracts-rfq", "license": "MIT", - "version": "0.8.0", + "version": "0.8.1", "description": "FastBridge contracts.", "private": true, "files": [ From 93f98863546d60486a6791930716994d3eba9c54 Mon Sep 17 00:00:00 2001 From: dwasse Date: Mon, 14 Oct 2024 10:18:13 -0500 Subject: [PATCH 33/47] feat(rfq-relayer): add MaxRelayAmount (#3259) * Feat: add quoteParams helper for test * Feat: add MaxQuoteAmount to relconfig * Feat: use MaxQuoteAmount * Feat: handle MaxQuoteAmount in quoter test * Replace: MaxQuoteAmount -> MaxRelayAmount * Feat: shouldProcess() returns false if max relay amount exceeded * Feat: add test for MaxRelayAmount --- services/rfq/relayer/quoter/quoter.go | 21 +++++- services/rfq/relayer/quoter/quoter_test.go | 82 +++++++++++++++++++--- services/rfq/relayer/relconfig/config.go | 2 + services/rfq/relayer/relconfig/getters.go | 35 +++++++++ 4 files changed, 128 insertions(+), 12 deletions(-) diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index 3b5ecc8352..2cd3dfcf94 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -207,6 +207,15 @@ func (m *Manager) ShouldProcess(parentCtx context.Context, quote reldb.QuoteRequ return false, nil } + // check relay amount + maxRelayAmount := m.config.GetMaxRelayAmount(int(quote.Transaction.OriginChainId), quote.Transaction.OriginToken) + if maxRelayAmount != nil { + if quote.Transaction.OriginAmount.Cmp(maxRelayAmount) > 0 { + span.AddEvent("origin amount is greater than max relay amount") + return false, nil + } + } + // all checks have passed return true, nil } @@ -713,7 +722,7 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, input QuoteInput) ( } } - // Finally, clip the quoteAmount by the dest balance + // Clip the quoteAmount by the dest balance if quoteAmount.Cmp(input.DestBalance) > 0 { span.AddEvent("quote amount greater than destination balance", trace.WithAttributes( attribute.String("quote_amount", quoteAmount.String()), @@ -722,6 +731,16 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, input QuoteInput) ( quoteAmount = input.DestBalance } + // Clip the quoteAmount by the maxQuoteAmount + maxQuoteAmount := m.config.GetMaxRelayAmount(input.DestChainID, input.DestTokenAddr) + if maxQuoteAmount != nil && quoteAmount.Cmp(maxQuoteAmount) > 0 { + span.AddEvent("quote amount greater than max quote amount", trace.WithAttributes( + attribute.String("quote_amount", quoteAmount.String()), + attribute.String("max_quote_amount", maxQuoteAmount.String()), + )) + quoteAmount = maxQuoteAmount + } + // Deduct gas cost from the quote amount, if necessary quoteAmount, err = m.deductGasCost(ctx, quoteAmount, input.DestTokenAddr, input.DestChainID) if err != nil { diff --git a/services/rfq/relayer/quoter/quoter_test.go b/services/rfq/relayer/quoter/quoter_test.go index 1d6a52c7de..321d55b189 100644 --- a/services/rfq/relayer/quoter/quoter_test.go +++ b/services/rfq/relayer/quoter/quoter_test.go @@ -136,6 +136,13 @@ func (s *QuoterSuite) TestShouldProcess() { s.False(s.manager.ShouldProcess(s.GetTestContext(), quote)) s.manager.SetRelayPaused(false) s.True(s.manager.ShouldProcess(s.GetTestContext(), quote)) + + // Set max relay amount + originTokenCfg := s.config.Chains[int(s.origin)].Tokens["USDC"] + originTokenCfg.MaxRelayAmount = "900" // less than balance + s.config.Chains[int(s.origin)].Tokens["USDC"] = originTokenCfg + s.manager.SetConfig(s.config) + s.False(s.manager.ShouldProcess(s.GetTestContext(), quote)) } func (s *QuoterSuite) TestIsProfitable() { @@ -173,13 +180,23 @@ func (s *QuoterSuite) TestGetOriginAmount() { originAddr := common.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48") balance := big.NewInt(1000_000_000) // 1000 USDC - setQuoteParams := func(quotePct, quoteOffset float64, minQuoteAmount, maxBalance string) { - s.config.BaseChainConfig.QuotePct = "ePct + type quoteParams struct { + quotePct float64 + quoteOffset float64 + minQuoteAmount string + maxBalance string + maxQuoteAmount string + } + + setQuoteParams := func(params quoteParams) { + s.config.BaseChainConfig.QuotePct = ¶ms.quotePct destTokenCfg := s.config.Chains[dest].Tokens["USDC"] - destTokenCfg.MinQuoteAmount = minQuoteAmount + destTokenCfg.MinQuoteAmount = params.minQuoteAmount + destTokenCfg.MaxRelayAmount = params.maxQuoteAmount originTokenCfg := s.config.Chains[origin].Tokens["USDC"] - originTokenCfg.QuoteOffsetBps = quoteOffset - originTokenCfg.MaxBalance = &maxBalance + originTokenCfg.QuoteOffsetBps = params.quoteOffset + originTokenCfg.MaxBalance = ¶ms.maxBalance + originTokenCfg.MaxRelayAmount = params.maxQuoteAmount s.config.Chains[dest].Tokens["USDC"] = destTokenCfg s.config.Chains[origin].Tokens["USDC"] = originTokenCfg s.manager.SetConfig(s.config) @@ -201,42 +218,85 @@ func (s *QuoterSuite) TestGetOriginAmount() { s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 50 with MinQuoteAmount of 0; should be 50% of balance. - setQuoteParams(50, 0, "0", "0") + setQuoteParams(quoteParams{ + quotePct: 50, + quoteOffset: 0, + minQuoteAmount: "0", + maxBalance: "0", + }) quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 50 with QuoteOffset of -1%. Should be 1% less than 50% of balance. - setQuoteParams(50, -100, "0", "0") + setQuoteParams(quoteParams{ + quotePct: 50, + quoteOffset: -100, + minQuoteAmount: "0", + maxBalance: "0", + }) quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount = big.NewInt(495_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 500; should be 50% of balance. - setQuoteParams(25, 0, "500", "0") + setQuoteParams(quoteParams{ + quotePct: 25, + quoteOffset: 0, + minQuoteAmount: "500", + maxBalance: "0", + }) quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 500; should be 50% of balance. - setQuoteParams(25, 0, "500", "0") + setQuoteParams(quoteParams{ + quotePct: 25, + quoteOffset: 0, + minQuoteAmount: "500", + maxBalance: "0", + }) quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 1500; should be total balance. - setQuoteParams(25, 0, "1500", "0") + setQuoteParams(quoteParams{ + quotePct: 25, + quoteOffset: 0, + minQuoteAmount: "1500", + maxBalance: "0", + }) quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount = big.NewInt(1000_000_000) s.Equal(expectedAmount, quoteAmount) + // Set QuotePct to 100 with MinQuoteAmount of 0 and MaxRelayAmount of 500; should be 500. + setQuoteParams(quoteParams{ + quotePct: 100, + quoteOffset: 0, + minQuoteAmount: "0", + maxBalance: "0", + maxQuoteAmount: "500", + }) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) + s.NoError(err) + expectedAmount = big.NewInt(500_000_000) + s.Equal(expectedAmount, quoteAmount) + // Set QuotePct to 25 with MinQuoteAmount of 1500 and MaxBalance of 1200; should be 200. - setQuoteParams(25, 0, "1500", "1200") + setQuoteParams(quoteParams{ + quotePct: 25, + quoteOffset: 0, + minQuoteAmount: "1500", + maxBalance: "1200", + }) quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount = big.NewInt(200_000_000) diff --git a/services/rfq/relayer/relconfig/config.go b/services/rfq/relayer/relconfig/config.go index a4449bf8db..220627e13a 100644 --- a/services/rfq/relayer/relconfig/config.go +++ b/services/rfq/relayer/relconfig/config.go @@ -124,6 +124,8 @@ type TokenConfig struct { PriceUSD float64 `yaml:"price_usd"` // MinQuoteAmount is the minimum amount to quote for this token in human-readable units. MinQuoteAmount string `yaml:"min_quote_amount"` + // MaxRelayAmount is the maximum amount to quote and relay for this token in human-readable units. + MaxRelayAmount string `yaml:"max_relay_amount"` // RebalanceMethods are the supported methods for rebalancing. RebalanceMethods []string `yaml:"rebalance_methods"` // MaintenanceBalancePct is the percentage of the total balance under which a rebalance will be triggered. diff --git a/services/rfq/relayer/relconfig/getters.go b/services/rfq/relayer/relconfig/getters.go index 2cb4880712..a3fbb25cc7 100644 --- a/services/rfq/relayer/relconfig/getters.go +++ b/services/rfq/relayer/relconfig/getters.go @@ -746,6 +746,41 @@ func (c Config) GetMinQuoteAmount(chainID int, addr common.Address) *big.Int { return quoteAmountScaled } +var defaultMaxRelayAmount *big.Int // nil + +// GetMaxRelayAmount returns the quote amount for the given chain and address. +// Note that this getter returns the value in native token decimals. +func (c Config) GetMaxRelayAmount(chainID int, addr common.Address) *big.Int { + chainCfg, ok := c.Chains[chainID] + if !ok { + return defaultMaxRelayAmount + } + + var tokenCfg *TokenConfig + for _, cfg := range chainCfg.Tokens { + if common.HexToAddress(cfg.Address).Hex() == addr.Hex() { + cfgCopy := cfg + tokenCfg = &cfgCopy + break + } + } + if tokenCfg == nil { + return defaultMaxRelayAmount + } + quoteAmountFlt, ok := new(big.Float).SetString(tokenCfg.MaxRelayAmount) + if !ok { + return defaultMaxRelayAmount + } + if quoteAmountFlt.Cmp(big.NewFloat(0)) <= 0 { + return defaultMaxRelayAmount + } + + // Scale the minQuoteAmount by the token decimals. + denomDecimalsFactor := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(tokenCfg.Decimals)), nil) + quoteAmountScaled, _ := new(big.Float).Mul(quoteAmountFlt, new(big.Float).SetInt(denomDecimalsFactor)).Int(nil) + return quoteAmountScaled +} + var defaultMinRebalanceAmount = big.NewInt(1000) // GetMinRebalanceAmount returns the min rebalance amount for the given chain and address. From e9f7adf9ffb867ee7e13cfc89a08d08b67705e02 Mon Sep 17 00:00:00 2001 From: aureliusbtc <82057759+aureliusbtc@users.noreply.github.com> Date: Mon, 14 Oct 2024 18:05:42 -0400 Subject: [PATCH 34/47] update bl --- packages/synapse-interface/public/blacklist.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/synapse-interface/public/blacklist.json b/packages/synapse-interface/public/blacklist.json index f018d998e9..baf4815770 100644 --- a/packages/synapse-interface/public/blacklist.json +++ b/packages/synapse-interface/public/blacklist.json @@ -557,5 +557,6 @@ "0x6fdb264a876c811c7e101ee7a4f4fe7704ecbb72", "0xb584050909a300fa0306b29f72e63dc4615b6f53", "0xA963df55B326609a0cd205e85ca92d2a3c94DaB5", - "0x0605eDeE6a8b8b553caE09Abe83b2ebeb75516eC" + "0x0605eDeE6a8b8b553caE09Abe83b2ebeb75516eC", + "0x4c968f6beecf1906710b08e8b472b8ba6e75f957" ] From 99cf53e44297af1781af6da1cb204e44c73b569f Mon Sep 17 00:00:00 2001 From: aureliusbtc <82057759+aureliusbtc@users.noreply.github.com> Date: Mon, 14 Oct 2024 18:08:10 -0400 Subject: [PATCH 35/47] update bl --- packages/synapse-interface/public/blacklist.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/synapse-interface/public/blacklist.json b/packages/synapse-interface/public/blacklist.json index baf4815770..21ddc573ba 100644 --- a/packages/synapse-interface/public/blacklist.json +++ b/packages/synapse-interface/public/blacklist.json @@ -558,5 +558,6 @@ "0xb584050909a300fa0306b29f72e63dc4615b6f53", "0xA963df55B326609a0cd205e85ca92d2a3c94DaB5", "0x0605eDeE6a8b8b553caE09Abe83b2ebeb75516eC", - "0x4c968f6beecf1906710b08e8b472b8ba6e75f957" + "0x4c968f6beecf1906710b08e8b472b8ba6e75f957", + "0xff3a8d02109393726a90c04d7afd76e2d571890e" ] From cfed271a10edae07fc7c5d1fb7856dbca6d06203 Mon Sep 17 00:00:00 2001 From: abtestingalpha <104046418+abtestingalpha@users.noreply.github.com> Date: Mon, 14 Oct 2024 21:06:06 -0400 Subject: [PATCH 36/47] Fixes typos (#3290) --- docs/bridge/docs/02-Bridge/01-SDK.md | 112 ++++++++++++++------------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/docs/bridge/docs/02-Bridge/01-SDK.md b/docs/bridge/docs/02-Bridge/01-SDK.md index c58d7e3f51..29687f414c 100644 --- a/docs/bridge/docs/02-Bridge/01-SDK.md +++ b/docs/bridge/docs/02-Bridge/01-SDK.md @@ -10,25 +10,25 @@ The Synapse Bridge SDK is built on top of the [Synapse Router](/docs/Routers/Syn ### Use cases -* Integrate your front-end application with the Synapse Bridge. -* Provide bridge liquidity. -* Perform cross-chain arbitrage. -* Integrate the Synapse Javascript SDK with your non-Javascript application. +- Integrate your front-end application with the Synapse Bridge. +- Provide bridge liquidity. +- Perform cross-chain arbitrage. +- Integrate the Synapse Javascript SDK with your non-Javascript application. ## Install :::note requires Node v16+ -The SDK has only been fully tested on Node 16+ or greater. Earlier versions are not guaranteed to work. +The SDK has only been fully tested on Node 16+ or greater. Earlier versions are not guaranteed to work. ::: -Requires either the `npx` or `yarn` package manager. +Requires either the `npm` or `yarn` package manager. | Options |- -| `npx install @synapsecns/sdk-router` -| `yarn install @synapsecns/sdk-router` +| `npm install @synapsecns/sdk-router` +| `yarn add @synapsecns/sdk-router` ## Configure Ethers @@ -60,8 +60,9 @@ const Synapse = new SynapseSDK(chainIds, providers) :::tip Ethers v6 Use of Ethers v6 requires the `@ethersproject/providers` dependency to be installed via `npm` or `yarn`: -* `npm install @ethersproject/providers@^5.7.2` -* `yarn add @ethersproject/providers@^5.7.2` + +- `npm install @ethersproject/providers@^5.7.2` +- `yarn add @ethersproject/providers@^5.7.2` ::: @@ -90,11 +91,11 @@ const Synapse = new SynapseSDK(chainIds, providers) `originQuery` and `destQuery`, returned by `bridgeQuote()` and required for `bridge()`, are [`Query`](https://synapserouter.gitbook.io/untitled/) objects, which contain: -* `swapAdapter`: (string): 0x address of the swap adapter. -* `tokenOut`: (string): 0x address of the outputted token on that chain. -* `minAmountOut`: (Ethers BigNumber): The min amount of value exiting the transaction. -* `deadline`: (Ethers BigNumber): The deadline for the potential transaction. -* `rawParams`: (string): 0x params for the potential transaction. +- `swapAdapter`: (string): 0x address of the swap adapter. +- `tokenOut`: (string): 0x address of the outputted token on that chain. +- `minAmountOut`: (Ethers BigNumber): The min amount of value exiting the transaction. +- `deadline`: (Ethers BigNumber): The deadline for the potential transaction. +- `rawParams`: (string): 0x params for the potential transaction. ::: @@ -106,25 +107,25 @@ Get all relevant information regarding a possible transaction. `bridgeQuote()` requires the following arguments: -* `fromChain` (number): Origin chain id. -* `toChain` (number): Destination chain id. -* `fromToken` (string): 0x token address on the origin chain. -* `toToken` (string): 0x token address on the destination chain. -* `amount` (Ethers BigNumber): The amount (with the correct amount of decimals specified by the token on the origin chain) -* `object` (three seperate args): -* `deadline` (Ethers BigNumber): Deadline for the transaction to be initiated on the origin chain, in seconds (optional) -* `originUserAddress` (string): Address of the user on the origin chain, optional, mandatory if a smart contract is going to initiate the bridge operation -* `excludedModules` (array): (optional) List of bridge modules to exclude from the result +- `fromChain` (number): Origin chain id. +- `toChain` (number): Destination chain id. +- `fromToken` (string): 0x token address on the origin chain. +- `toToken` (string): 0x token address on the destination chain. +- `amount` (Ethers BigNumber): The amount (with the correct amount of decimals specified by the token on the origin chain) +- An `object` with three separate args: + - `deadline` (Ethers BigNumber): Deadline for the transaction to be initiated on the origin chain, in seconds (optional) + - `originUserAddress` (string): Address of the user on the origin chain, optional, mandatory if a smart contract is going to initiate the bridge operation + - `excludedModules` (array): (optional) List of bridge modules to exclude from the result #### Return value `bridgeQuote` returns the following information -* `feeAmount` (Ethers BigNumber): The calculated amount of fee to be taken. -* `bridgeFee` (number): The percentage of fee to be taken. -* `maxAmountOut` (Ethers BigNumber): The maximum output amount resulting from the bridge transaction. -* `originQuery` (`Query`): The query to be executed on the origin chain. -* `destQuery` (`Query`): The query to be executed on the destination chain. +- `feeAmount` (Ethers BigNumber): The calculated amount of fee to be taken. +- `bridgeFee` (number): The percentage of fee to be taken. +- `maxAmountOut` (Ethers BigNumber): The maximum output amount resulting from the bridge transaction. +- `originQuery` (`Query`): The query to be executed on the origin chain. +- `destQuery` (`Query`): The query to be executed on the destination chain. ### `bridge()` @@ -132,19 +133,19 @@ Use `bridgeQuote` to request a Bridge transaction #### Parameters -* `toAddress` (number): The 0x wallet address on the destination chain. -* `routerAddress` (string): The 0x contract address on the origin chain of the bridge router contract. -* `fromChain` (number): The origin chain id. -* `toChain` (number): The destination chain id. -* `fromToken` (string): The 0x token address on the origin chain. -* `amount` (Ethers BigNumber): The amount (with the correct amount of decimals specified by the token on the origin chain) -* `originQuery` (`Query`): The query to be executed on the origin chain. -* `destQuery` (`Query`): The query to be executed on the destination chain. +- `toAddress` (number): The 0x wallet address on the destination chain. +- `routerAddress` (string): The 0x contract address on the origin chain of the bridge router contract. +- `fromChain` (number): The origin chain id. +- `toChain` (number): The destination chain id. +- `fromToken` (string): The 0x token address on the origin chain. +- `amount` (Ethers BigNumber): The amount (with the correct amount of decimals specified by the token on the origin chain) +- `originQuery` (`Query`): The query to be executed on the origin chain. +- `destQuery` (`Query`): The query to be executed on the destination chain. #### Return value -* `to` (string): 0x wallet address on the destination chain. -* `data` (string): Output data in 0x hex format +- `to` (string): 0x wallet address on the destination chain. +- `data` (string): Output data in 0x hex format ### `allBridgeQuotes()` @@ -165,7 +166,7 @@ const quotes = await Synapse.bridgeQuote( 43114, // Destination Chain '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', // Origin Token Address '0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664', // Destination Token Address - BigNumber.from('20000000') // Amount in + BigNumber.from('20000000') // Amount in { // Deadline for the transaction to be initiated on the origin chain, in seconds (optional) deadline: 1234567890, @@ -183,14 +184,14 @@ const quotes = await Synapse.bridgeQuote( ```js await Synapse.bridge( - '0x0AF91FA049A7e1894F480bFE5bBa20142C6c29a9', // To Address - bridgeQuote.routerAddress, // address of the contract to route the txn - 42161, // Origin Chain - 43114, // Destination Chain - '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', // Origin Token Address - BigNumber.from('20000000'), // Amount - quote.originQuery, // Origin query from bridgeQuote() - quote.destQuery // Destination query from bridgeQuote() + '0x0AF91FA049A7e1894F480bFE5bBa20142C6c29a9', // To Address + bridgeQuote.routerAddress, // address of the contract to route the txn + 42161, // Origin Chain + 43114, // Destination Chain + '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', // Origin Token Address + BigNumber.from('20000000'), // Amount + quote.originQuery, // Origin query from bridgeQuote() + quote.destQuery // Destination query from bridgeQuote() ) ``` @@ -198,22 +199,23 @@ await Synapse.bridge( ### Options object -* `deadline`, `excludeCCTP` (now `excludedModules`), and `originUserAddress` parameters are now found in an (optional) options object at the end of the arguments list for `bridgeQuote()`, and `allBridgeQuotes()`. -* `excludedModules` excludes one or more modules with an array of the module names. Supported names are `SynapseBridge`, `SynapseCCTP`, and `SynapseRFQ`. -* `originUserAddress` is required as part of the options object to initiate a bridge transaction on behalf of a user. +- `deadline`, `excludeCCTP` (now `excludedModules`), and `originUserAddress` parameters are now found in an (optional) options object at the end of the arguments list for `bridgeQuote()`, and `allBridgeQuotes()`. +- `excludedModules` excludes one or more modules with an array of the module names. Supported names are `SynapseBridge`, `SynapseCCTP`, and `SynapseRFQ`. +- `originUserAddress` is required as part of the options object to initiate a bridge transaction on behalf of a user. ### Examples + ```js bridgeQuote(...arguments, { deadline: 1234567890, - excludedModules: ["SynapseCCTP"], - originUserAddress: "0x1234...", + excludedModules: ['SynapseCCTP'], + originUserAddress: '0x1234...', }) allBridgeQuotes({ deadline: 1234567890, - excludedModules: ["SynapseCCTP"], - originUserAddress: "0x1234...", + excludedModules: ['SynapseCCTP'], + originUserAddress: '0x1234...', }) ``` From e0ce7e71db0b100d5345a4b76446d42f5433220f Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Tue, 15 Oct 2024 01:10:16 +0000 Subject: [PATCH 37/47] Publish - @synapsecns/bridge-docs@0.4.3 - @synapsecns/synapse-interface@0.40.9 --- docs/bridge/CHANGELOG.md | 8 ++++++++ docs/bridge/package.json | 2 +- packages/synapse-interface/CHANGELOG.md | 8 ++++++++ packages/synapse-interface/package.json | 2 +- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/bridge/CHANGELOG.md b/docs/bridge/CHANGELOG.md index d7f5871ab9..6aae6f9de8 100644 --- a/docs/bridge/CHANGELOG.md +++ b/docs/bridge/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.4.3](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.4.2...@synapsecns/bridge-docs@0.4.3) (2024-10-15) + +**Note:** Version bump only for package @synapsecns/bridge-docs + + + + + ## [0.4.2](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.4.1...@synapsecns/bridge-docs@0.4.2) (2024-10-12) diff --git a/docs/bridge/package.json b/docs/bridge/package.json index 2e2d1bb267..f3bb4e55a7 100644 --- a/docs/bridge/package.json +++ b/docs/bridge/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/bridge-docs", - "version": "0.4.2", + "version": "0.4.3", "private": true, "scripts": { "docusaurus": "docusaurus", diff --git a/packages/synapse-interface/CHANGELOG.md b/packages/synapse-interface/CHANGELOG.md index 0895428ebb..e6a6670415 100644 --- a/packages/synapse-interface/CHANGELOG.md +++ b/packages/synapse-interface/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.40.9](https://github.com/synapsecns/sanguine/compare/@synapsecns/synapse-interface@0.40.8...@synapsecns/synapse-interface@0.40.9) (2024-10-15) + +**Note:** Version bump only for package @synapsecns/synapse-interface + + + + + ## [0.40.8](https://github.com/synapsecns/sanguine/compare/@synapsecns/synapse-interface@0.40.7...@synapsecns/synapse-interface@0.40.8) (2024-10-11) **Note:** Version bump only for package @synapsecns/synapse-interface diff --git a/packages/synapse-interface/package.json b/packages/synapse-interface/package.json index 0efdd27a49..7acf6c7973 100644 --- a/packages/synapse-interface/package.json +++ b/packages/synapse-interface/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/synapse-interface", - "version": "0.40.8", + "version": "0.40.9", "private": true, "engines": { "node": ">=18.18.0" From ea0154c23055972583af3ba1a31cbb6d86cfdbd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CF=87=C2=B2?= <88190723+ChiTimesChi@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:32:44 +0100 Subject: [PATCH 38/47] test(contracts-rfq): remove test contracts from coverage report (#3291) * test: remove old test contracts from coverage * test: remove new test contracts from coverage --- packages/contracts-rfq/script/FastBridge.s.sol | 3 +++ packages/contracts-rfq/test/FastBridgeMock.sol | 3 +++ packages/contracts-rfq/test/FastBridgeV2.Dst.Base.t.sol | 5 ++++- .../test/FastBridgeV2.GasBench.Dst.ArbitraryCall.t.sol | 5 ++++- .../contracts-rfq/test/FastBridgeV2.GasBench.Dst.Excl.t.sol | 5 ++++- .../test/FastBridgeV2.GasBench.Src.ArbitraryCall.t.sol | 5 ++++- .../test/FastBridgeV2.GasBench.Src.PFees.t.sol | 5 ++++- .../contracts-rfq/test/FastBridgeV2.Src.ProtocolFees.t.sol | 5 ++++- packages/contracts-rfq/test/FastBridgeV2.t.sol | 3 +++ packages/contracts-rfq/test/MockERC20.sol | 4 ++++ packages/contracts-rfq/test/UniversalTokenLibHarness.sol | 5 ++++- .../contracts-rfq/test/harnesses/MulticallTargetHarness.sol | 4 ++++ .../test/mocks/ExcessiveReturnValueRecipient.sol | 4 ++++ .../test/mocks/IncorrectReturnValueRecipient.sol | 4 ++++ .../contracts-rfq/test/mocks/NoReturnValueRecipient.sol | 6 ++++-- packages/contracts-rfq/test/mocks/NonPayableRecipient.sol | 4 ++++ packages/contracts-rfq/test/mocks/RecipientMock.sol | 4 ++++ 17 files changed, 65 insertions(+), 9 deletions(-) diff --git a/packages/contracts-rfq/script/FastBridge.s.sol b/packages/contracts-rfq/script/FastBridge.s.sol index 84d048575d..de3208889f 100644 --- a/packages/contracts-rfq/script/FastBridge.s.sol +++ b/packages/contracts-rfq/script/FastBridge.s.sol @@ -7,6 +7,9 @@ import {Script} from "forge-std/Script.sol"; contract DeployFastBridge is Script { FastBridge public bridge; + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testDeployFastBridge() external {} + /// e.g. forge script contracts/script/FastBridge.s.sol --sig "run(address, address[])" 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 "[0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f]" function run(address owner, address[] memory relayers) external { vm.startBroadcast(); diff --git a/packages/contracts-rfq/test/FastBridgeMock.sol b/packages/contracts-rfq/test/FastBridgeMock.sol index 0f035c3430..a84ce7db72 100644 --- a/packages/contracts-rfq/test/FastBridgeMock.sol +++ b/packages/contracts-rfq/test/FastBridgeMock.sol @@ -16,6 +16,9 @@ contract FastBridgeMock is IFastBridge, Admin { /// @dev to prevent replays uint256 public nonce; + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testFastBridgeMock() external {} + function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) { return abi.decode(request, (BridgeTransaction)); } diff --git a/packages/contracts-rfq/test/FastBridgeV2.Dst.Base.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Dst.Base.t.sol index 9e79e48489..f499136cfe 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Dst.Base.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Dst.Base.t.sol @@ -3,10 +3,13 @@ pragma solidity ^0.8.20; import {FastBridgeV2, FastBridgeV2Test, IFastBridgeV2} from "./FastBridgeV2.t.sol"; -// solhint-disable func-name-mixedcase, ordering +// solhint-disable func-name-mixedcase, no-empty-blocks contract FastBridgeV2DstBaseTest is FastBridgeV2Test { uint256 public constant LEFTOVER_BALANCE = 1 ether; + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testFastBridgeV2DstBaseTest() external {} + function setUp() public virtual override { vm.chainId(DST_CHAIN_ID); super.setUp(); diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.ArbitraryCall.t.sol index 1fe2da38ab..55958e937f 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.ArbitraryCall.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.ArbitraryCall.t.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.20; import {FastBridgeV2GasBenchmarkDstTest} from "./FastBridgeV2.GasBench.Dst.t.sol"; import {RecipientMock} from "./mocks/RecipientMock.sol"; -// solhint-disable func-name-mixedcase, ordering +// solhint-disable func-name-mixedcase, no-empty-blocks contract FastBridgeV2GasBenchmarkDstArbitraryCallTest is FastBridgeV2GasBenchmarkDstTest { // To get an idea about how much overhead the arbitrary call adds to the relaying process, we use a mock // recipient that has the hook function implemented as a no-op. @@ -12,6 +12,9 @@ contract FastBridgeV2GasBenchmarkDstArbitraryCallTest is FastBridgeV2GasBenchmar // - user address // - some kind of ID to decide what to do with the tokens next + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testFastBridgeV2GasBenchmarkDstArbitraryCallTest() external {} + function setUp() public virtual override { // In the inherited tests userB is always used as the recipient of the tokens. userB = address(new RecipientMock()); diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.Excl.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.Excl.t.sol index 685dab76a4..970f51465b 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.Excl.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.Excl.t.sol @@ -3,10 +3,13 @@ pragma solidity ^0.8.20; import {FastBridgeV2GasBenchmarkDstTest} from "./FastBridgeV2.GasBench.Dst.t.sol"; -// solhint-disable func-name-mixedcase, ordering +// solhint-disable func-name-mixedcase, no-empty-blocks contract FastBridgeV2GasBenchmarkDstExclusivityTest is FastBridgeV2GasBenchmarkDstTest { uint256 public constant EXCLUSIVITY_PERIOD = 60 seconds; + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testFastBridgeV2GasBenchmarkDstExclusivityTest() external {} + function setUp() public virtual override { super.setUp(); skip({time: EXCLUSIVITY_PERIOD / 2}); diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.ArbitraryCall.t.sol index e806f27544..d9291b8208 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.ArbitraryCall.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.ArbitraryCall.t.sol @@ -3,8 +3,11 @@ pragma solidity ^0.8.20; import {FastBridgeV2GasBenchmarkSrcTest} from "./FastBridgeV2.GasBench.Src.t.sol"; -// solhint-disable func-name-mixedcase, ordering +// solhint-disable func-name-mixedcase, no-empty-blocks contract FastBridgeV2GasBenchmarkSrcArbitraryCallTest is FastBridgeV2GasBenchmarkSrcTest { + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testFastBridgeV2GasBenchmarkSrcArbitraryCallTest() external {} + function createFixturesV2() public virtual override { super.createFixturesV2(); bytes memory mockCallParams = abi.encode(userA, keccak256("Random ID")); diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.PFees.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.PFees.t.sol index 51f17b5a96..790db012f6 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.PFees.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.PFees.t.sol @@ -3,8 +3,11 @@ pragma solidity ^0.8.20; import {FastBridgeV2GasBenchmarkSrcTest} from "./FastBridgeV2.GasBench.Src.t.sol"; -// solhint-disable func-name-mixedcase, ordering +// solhint-disable func-name-mixedcase, no-empty-blocks contract FastBridgeV2GasBenchmarkSrcProtocolFeesTest is FastBridgeV2GasBenchmarkSrcTest { + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testFastBridgeV2GasBenchmarkSrcProtocolFeesTest() external {} + function configureFastBridge() public virtual override { super.configureFastBridge(); fastBridge.grantRole(fastBridge.GOVERNOR_ROLE(), address(this)); diff --git a/packages/contracts-rfq/test/FastBridgeV2.Src.ProtocolFees.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Src.ProtocolFees.t.sol index d9a5324ed1..775ff257e5 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Src.ProtocolFees.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Src.ProtocolFees.t.sol @@ -3,8 +3,11 @@ pragma solidity ^0.8.20; import {FastBridgeV2SrcTest} from "./FastBridgeV2.Src.t.sol"; -// solhint-disable func-name-mixedcase, ordering +// solhint-disable func-name-mixedcase, no-empty-blocks contract FastBridgeV2SrcProtocolFeesTest is FastBridgeV2SrcTest { + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testFastBridgeV2SrcProtocolFeesTest() external {} + function configureFastBridge() public virtual override { super.configureFastBridge(); fastBridge.grantRole(fastBridge.GOVERNOR_ROLE(), address(this)); diff --git a/packages/contracts-rfq/test/FastBridgeV2.t.sol b/packages/contracts-rfq/test/FastBridgeV2.t.sol index fca2bad7c3..1a0c3645a3 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.t.sol @@ -44,6 +44,9 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { IFastBridgeV2.BridgeParamsV2 internal tokenParamsV2; IFastBridgeV2.BridgeParamsV2 internal ethParamsV2; + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testFastBridgeV2Test() external {} + function setUp() public virtual { srcToken = new MockERC20("SrcToken", 6); dstToken = new MockERC20("DstToken", 6); diff --git a/packages/contracts-rfq/test/MockERC20.sol b/packages/contracts-rfq/test/MockERC20.sol index f4c07d49aa..b0e2f67d99 100644 --- a/packages/contracts-rfq/test/MockERC20.sol +++ b/packages/contracts-rfq/test/MockERC20.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.17; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +// solhint-disable no-empty-blocks contract MockERC20 is ERC20 { uint8 private _decimals; @@ -10,6 +11,9 @@ contract MockERC20 is ERC20 { _decimals = decimals_; } + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testMockERC20() external {} + function burn(address account, uint256 amount) external { _burn(account, amount); } diff --git a/packages/contracts-rfq/test/UniversalTokenLibHarness.sol b/packages/contracts-rfq/test/UniversalTokenLibHarness.sol index 7f8d2d6753..5e628b5fa2 100644 --- a/packages/contracts-rfq/test/UniversalTokenLibHarness.sol +++ b/packages/contracts-rfq/test/UniversalTokenLibHarness.sol @@ -3,8 +3,11 @@ pragma solidity ^0.8.17; import {UniversalTokenLib} from "../contracts/libs/UniversalToken.sol"; -// solhint-disable ordering +// solhint-disable no-empty-blocks, ordering contract UniversalTokenLibHarness { + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testUniversalTokenLibHarness() external {} + function universalTransfer(address token, address to, uint256 value) public { UniversalTokenLib.universalTransfer(token, to, value); } diff --git a/packages/contracts-rfq/test/harnesses/MulticallTargetHarness.sol b/packages/contracts-rfq/test/harnesses/MulticallTargetHarness.sol index 5819dbf3fc..4a2e527f22 100644 --- a/packages/contracts-rfq/test/harnesses/MulticallTargetHarness.sol +++ b/packages/contracts-rfq/test/harnesses/MulticallTargetHarness.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.0; import {MulticallTarget} from "../../contracts/utils/MulticallTarget.sol"; +// solhint-disable no-empty-blocks contract MulticallTargetHarness is MulticallTarget { address public addressField; uint256 public uintField; @@ -11,6 +12,9 @@ contract MulticallTargetHarness is MulticallTarget { error CustomError(); + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testMulticallTargetHarness() external {} + function setMsgSenderAsAddressField() external returns (address) { addressField = msg.sender; return addressField; diff --git a/packages/contracts-rfq/test/mocks/ExcessiveReturnValueRecipient.sol b/packages/contracts-rfq/test/mocks/ExcessiveReturnValueRecipient.sol index 9c3be02502..21f3484dd7 100644 --- a/packages/contracts-rfq/test/mocks/ExcessiveReturnValueRecipient.sol +++ b/packages/contracts-rfq/test/mocks/ExcessiveReturnValueRecipient.sol @@ -3,11 +3,15 @@ pragma solidity ^0.8.0; import {IFastBridgeRecipient} from "../../contracts/interfaces/IFastBridgeRecipient.sol"; +// solhint-disable no-empty-blocks /// @notice Incorrectly implemented recipient mock for testing purposes. DO NOT USE IN PRODUCTION. contract ExcessiveReturnValueRecipient { /// @notice Mock needs to accept ETH receive() external payable {} + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testExcessiveReturnValueRecipient() external {} + /// @notice Incorrectly implemented - method returns excessive bytes. function fastBridgeTransferReceived(address, uint256, bytes memory) external payable returns (bytes4, uint256) { return (IFastBridgeRecipient.fastBridgeTransferReceived.selector, 1337); diff --git a/packages/contracts-rfq/test/mocks/IncorrectReturnValueRecipient.sol b/packages/contracts-rfq/test/mocks/IncorrectReturnValueRecipient.sol index 2bf955da7f..0570f49cd0 100644 --- a/packages/contracts-rfq/test/mocks/IncorrectReturnValueRecipient.sol +++ b/packages/contracts-rfq/test/mocks/IncorrectReturnValueRecipient.sol @@ -3,11 +3,15 @@ pragma solidity ^0.8.0; import {IFastBridgeRecipient} from "../../contracts/interfaces/IFastBridgeRecipient.sol"; +// solhint-disable no-empty-blocks /// @notice Incorrectly implemented recipient mock for testing purposes. DO NOT USE IN PRODUCTION. contract IncorrectReturnValueRecipient is IFastBridgeRecipient { /// @notice Mock needs to accept ETH receive() external payable {} + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testIncorrectReturnValueRecipient() external {} + /// @notice Incorrectly implemented - method returns incorrect value. function fastBridgeTransferReceived(address, uint256, bytes memory) external payable returns (bytes4) { // Flip the last bit diff --git a/packages/contracts-rfq/test/mocks/NoReturnValueRecipient.sol b/packages/contracts-rfq/test/mocks/NoReturnValueRecipient.sol index e10c8b6ded..1ba76e7402 100644 --- a/packages/contracts-rfq/test/mocks/NoReturnValueRecipient.sol +++ b/packages/contracts-rfq/test/mocks/NoReturnValueRecipient.sol @@ -1,13 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -// solhint-disable - +// solhint-disable no-empty-blocks /// @notice Incorrectly implemented recipient mock for testing purposes. DO NOT USE IN PRODUCTION. contract NoReturnValueRecipient { /// @notice Mock needs to accept ETH receive() external payable {} + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testNoReturnValueRecipient() external {} + /// @notice Incorrectly implemented - method does not return anything. function fastBridgeTransferReceived(address, uint256, bytes memory) external payable {} } diff --git a/packages/contracts-rfq/test/mocks/NonPayableRecipient.sol b/packages/contracts-rfq/test/mocks/NonPayableRecipient.sol index 1f53dabfd1..2c80581943 100644 --- a/packages/contracts-rfq/test/mocks/NonPayableRecipient.sol +++ b/packages/contracts-rfq/test/mocks/NonPayableRecipient.sol @@ -1,8 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable no-empty-blocks /// @notice Incorrectly implemented recipient mock for testing purposes. DO NOT USE IN PRODUCTION. contract NonPayableRecipient { + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testNonPayableRecipient() external {} + /// @notice Incorrectly implemented - method is not payable. function fastBridgeTransferReceived(address, uint256, bytes memory) external pure returns (bytes4) { return NonPayableRecipient.fastBridgeTransferReceived.selector; diff --git a/packages/contracts-rfq/test/mocks/RecipientMock.sol b/packages/contracts-rfq/test/mocks/RecipientMock.sol index a35d4ac5ec..f95422b322 100644 --- a/packages/contracts-rfq/test/mocks/RecipientMock.sol +++ b/packages/contracts-rfq/test/mocks/RecipientMock.sol @@ -3,11 +3,15 @@ pragma solidity ^0.8.0; import {IFastBridgeRecipient} from "../../contracts/interfaces/IFastBridgeRecipient.sol"; +// solhint-disable no-empty-blocks /// @notice Recipient mock for testing purposes. DO NOT USE IN PRODUCTION. contract RecipientMock is IFastBridgeRecipient { /// @notice Mock needs to accept ETH receive() external payable {} + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testRecipientMock() external {} + /// @notice Minimal viable implementation of the fastBridgeTransferReceived hook. function fastBridgeTransferReceived(address, uint256, bytes memory) external payable returns (bytes4) { return IFastBridgeRecipient.fastBridgeTransferReceived.selector; From b09b41c2a55efbca44e6daef27e723284e8137ea Mon Sep 17 00:00:00 2001 From: ChiTimesChi Date: Tue, 15 Oct 2024 13:37:06 +0000 Subject: [PATCH 39/47] Publish - @synapsecns/contracts-rfq@0.8.2 --- packages/contracts-rfq/CHANGELOG.md | 8 ++++++++ packages/contracts-rfq/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/contracts-rfq/CHANGELOG.md b/packages/contracts-rfq/CHANGELOG.md index 2cdda57ace..3c3f40bb2d 100644 --- a/packages/contracts-rfq/CHANGELOG.md +++ b/packages/contracts-rfq/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.8.2](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.8.1...@synapsecns/contracts-rfq@0.8.2) (2024-10-15) + +**Note:** Version bump only for package @synapsecns/contracts-rfq + + + + + ## [0.8.1](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.8.0...@synapsecns/contracts-rfq@0.8.1) (2024-10-14) **Note:** Version bump only for package @synapsecns/contracts-rfq diff --git a/packages/contracts-rfq/package.json b/packages/contracts-rfq/package.json index 45f09710e3..701ea12ed0 100644 --- a/packages/contracts-rfq/package.json +++ b/packages/contracts-rfq/package.json @@ -1,7 +1,7 @@ { "name": "@synapsecns/contracts-rfq", "license": "MIT", - "version": "0.8.1", + "version": "0.8.2", "description": "FastBridge contracts.", "private": true, "files": [ From cd85cadc6c7d490d3d71812339ebea473ce1091e Mon Sep 17 00:00:00 2001 From: parodime Date: Tue, 15 Oct 2024 12:29:50 -0400 Subject: [PATCH 40/47] +rfq-loadtest [SLT-349] (#3281) * +rfq-loadtest * lint * lint * lint * fix retry loop * yarn fix * scope package & set private * impv docs --------- Co-authored-by: Trajan0x --- docs/bridge/docs/04-Routers/RFQ/index.md | 4 + packages/rfq-loadtest/.gitignore | 11 + packages/rfq-loadtest/.vscode/launch.json | 26 + packages/rfq-loadtest/README.md | 61 ++ packages/rfq-loadtest/config-template.yaml | 70 ++ packages/rfq-loadtest/package.json | 34 + packages/rfq-loadtest/sql/ponderSummary.sql | 43 + packages/rfq-loadtest/src/abi.ts | 952 ++++++++++++++++++++ packages/rfq-loadtest/src/index.ts | 496 ++++++++++ packages/rfq-loadtest/src/pyRepeater.py | 11 + packages/rfq-loadtest/src/utils.ts | 34 + packages/rfq-loadtest/tsconfig.json | 16 + yarn.lock | 74 +- 13 files changed, 1822 insertions(+), 10 deletions(-) create mode 100644 packages/rfq-loadtest/.gitignore create mode 100644 packages/rfq-loadtest/.vscode/launch.json create mode 100644 packages/rfq-loadtest/README.md create mode 100644 packages/rfq-loadtest/config-template.yaml create mode 100644 packages/rfq-loadtest/package.json create mode 100644 packages/rfq-loadtest/sql/ponderSummary.sql create mode 100644 packages/rfq-loadtest/src/abi.ts create mode 100644 packages/rfq-loadtest/src/index.ts create mode 100644 packages/rfq-loadtest/src/pyRepeater.py create mode 100644 packages/rfq-loadtest/src/utils.ts create mode 100644 packages/rfq-loadtest/tsconfig.json diff --git a/docs/bridge/docs/04-Routers/RFQ/index.md b/docs/bridge/docs/04-Routers/RFQ/index.md index b44418cde1..b2a498f803 100644 --- a/docs/bridge/docs/04-Routers/RFQ/index.md +++ b/docs/bridge/docs/04-Routers/RFQ/index.md @@ -75,3 +75,7 @@ In a successful dispute, the relayer loses their claimable funds. This design is ## Unfulfilled requests If a request is not fulfilled, users can reclaim their funds by using the [`claim`](https://vercel-rfq-docs.vercel.app/contracts/FastBridge.sol/contract.FastBridge.html#claim) function once the optimistic window has passed. + +## Load Tester + +The [`rfq-loadtest`](https://github.com/synapsecns/sanguine/tree/master/packages/rfq-loadtest) tool can be used to rapidly send ETH bridges for the purpose of load testing. \ No newline at end of file diff --git a/packages/rfq-loadtest/.gitignore b/packages/rfq-loadtest/.gitignore new file mode 100644 index 0000000000..2d6baefbab --- /dev/null +++ b/packages/rfq-loadtest/.gitignore @@ -0,0 +1,11 @@ + +node_modules/ + +*.tsbuildinfo + +dist/ + +.env + +config*.yaml +!config-template.yaml diff --git a/packages/rfq-loadtest/.vscode/launch.json b/packages/rfq-loadtest/.vscode/launch.json new file mode 100644 index 0000000000..d15373c646 --- /dev/null +++ b/packages/rfq-loadtest/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "debugRun", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/src/index.ts", + "preLaunchTask": "npm: build", + "sourceMaps": true, + "smartStep": true, + "console": "internalConsole", + "internalConsoleOptions": "openOnSessionStart", + "args": ["--configFile", "config-dev.yaml", "--pKeyIndex", "5"], + "outFiles": [ + "${workspaceFolder}/dist/**/*.js" + ] + } + ] +} \ No newline at end of file diff --git a/packages/rfq-loadtest/README.md b/packages/rfq-loadtest/README.md new file mode 100644 index 0000000000..4af4152226 --- /dev/null +++ b/packages/rfq-loadtest/README.md @@ -0,0 +1,61 @@ +> :warning: **Warning**: This tool is not intended to be used for anything other than testing with inconsequentially small amounts of ETH on EOAs that were created for the sole & explicit purpose of testing. + +# RFQ Load Test Configuration Guide + +This guide outlines the steps and requirements for setting up the RFQ load testing tool. The tool is designed to send many ETH bridges in rapid succession. + +## Wallet Configuration + +- **Create and Fund Wallets:** You are required to create and fund as many wallets as you wish to test with. This tool only supports native ETH bridges on chains that use ETH as the gas currency. + +- **Auto-Rebalance:** If you only initially fund ETH on one of the test chains, the tool will automatically rebalance the funds to the other chains before beginning the tests. It will also rebalance as needed while the tests are operating until none of the test chains have enough ETH to effectively rebalance to the others - at which point it will cease the process. The RFQ system is also used for these rebalance actions. + + +# Script Configuration + +Follow these steps to configure your load testing environment for blockchain transactions. + +## Step 1: Prepare Configuration File + +1. Start by copying the `config-template.yaml` file from the `packages/rfq-loadtest` directory. This will serve as the basis for your test configuration. + ```bash + cp packages/rfq-loadtest/config-template.yaml packages/rfq-loadtest/config-run.yaml + ``` + +## Step 2: Configure Private Keys + +2. Open the `config-run.yaml` file and locate the `PRIVATE_KEY_X` entries. Replace the placeholder values with your actual private keys. These keys will be used to execute transactions during the tests. + ```yaml + PRIVATE_KEY_1: 'your_private_key_here' + PRIVATE_KEY_2: 'your_private_key_here' + PRIVATE_KEY_3: 'your_private_key_here' + PRIVATE_KEY_4: 'your_private_key_here' + PRIVATE_KEY_5: 'your_private_key_here' + ``` + +## Step 3: Set Transaction Pace + +3. Adjust the settings under `##### TEST PACE` to control the pace of transactions. You can modify the `VOLLEY_MILLISECONDS_BETWEEN`, `VOLLEY_MIN_COUNT`, and `VOLLEY_MAX_COUNT` to fit your testing requirements. + +## Step 4: Specify Test Bridge Amount + +4. Define the amount of ETH to be sent in each test transaction under `TEST_BRIDGE_AMOUNT_UNITS`. The default is set to `0.00007`. + +## Step 5: Configure Gas and Rebalance Settings + +5. Set the `MINIMUM_GAS_UNITS` to the desired threshold for triggering a rebalance of funds across chains. Specify the `REBALANCE_TO_UNITS` to determine the target amount for each chain after rebalancing. + +## Step 6: Define Chain Settings + +6. In the `CHAINS` section, configure the `FastRouterAddr` and `rpcUrl` settings for each chain involved in your tests. These settings include URLs for reading, simulation, and submitting transactions. + +## Step 7: Configure Test Routes + +7. Under `TEST_ROUTES`, define the routes for your test transactions, including `fromChainId`, `toChainId`, and `testDistributionPercentage` to control the flow and distribution of transactions between chains. + +## Step 8: Save and Run + +8. Save your changes to `config-run.yaml`. To start the load test, use the provided startup example, adjusting the path to your configuration file as necessary. + ```bash + python3 pyRepeater.py 'node index.js --configFile ../config-run.yaml --pKeyIndex 1' + ``` diff --git a/packages/rfq-loadtest/config-template.yaml b/packages/rfq-loadtest/config-template.yaml new file mode 100644 index 0000000000..0727058300 --- /dev/null +++ b/packages/rfq-loadtest/config-template.yaml @@ -0,0 +1,70 @@ + +# create & fund however many wallets you want to test with. +# only supports native ETH bridges on chains that use ETH as gas. +# if you only fund ETH on one of the test chains it will auto-rebalance the funds to the others before beginning tests. + +# Startup example w/ pyRepeater to auto-restart the process if anything kills it +# python3 pyRepeater.py 'node index.js --configFile ../config-prod.yaml --pKeyIndex 1' + +PRIVATE_KEY_1: '0xabcdef123456abcdef123456abcdef123456abcdef123456abcdef123456abcd' +PRIVATE_KEY_2: '0xabcdef123456abcdef123456abcdef123456abcdef123456abcdef123456abcd' +PRIVATE_KEY_3: '0xabcdef123456abcdef123456abcdef123456abcdef123456abcdef123456abcd' +PRIVATE_KEY_4: '0xabcdef123456abcdef123456abcdef123456abcdef123456abcdef123456abcd' +PRIVATE_KEY_5: '0xabcdef123456abcdef123456abcdef123456abcdef123456abcdef123456abcd' + +##### TEST PACE +# these settings are a pace of about 100K deposits per day +# +# how long to wait in btwn each volley? +VOLLEY_MILLISECONDS_BETWEEN: 5500 +# each volley sends a batch of between {min} and {max} transactions +VOLLEY_MIN_COUNT: 1 +VOLLEY_MAX_COUNT: 5 + +# these settings are a pace of about 150K deposits per day +#VOLLEY_MILLISECONDS_BETWEEN: 5500 +#VOLLEY_MIN_COUNT: 1 +#VOLLEY_MAX_COUNT: 5 + +# approx how much ETH to send on each test bridge? 0.00007 +TEST_BRIDGE_AMOUNT_UNITS: 0.00007 + +# trigger a rebalance when gas reaches this value or lower +MINIMUM_GAS_UNITS: 0.003 + +# when a rebalance is triggered, resupply the deficit chain to this amount +REBALANCE_TO_UNITS: 0.01 + +CHAINS: + 10: + FastRouterAddr: '0x00cd000000003f7f682be4813200893d4e690000' + # urls used for Reading / Tx Simulation / Tx Submit -- respectively. Change to others as needed. + rpcUrl_Read: 'https://mainnet.optimism.io' + rpcUrl_Sim: 'https://mainnet.optimism.io' + rpcUrl_Write: 'https://mainnet.optimism.io' + 8453: + FastRouterAddr: '0x00cd000000003f7f682be4813200893d4e690000' + # urls used for Reading / Tx Simulation / Tx Submit -- respectively. Change to others as needed. + rpcUrl_Read: 'https://mainnet.base.org' + rpcUrl_Sim: 'https://mainnet.base.org' + rpcUrl_Write: 'https://mainnet.base.org' + 480: + FastRouterAddr: '0x00cd000000003f7f682be4813200893d4e690000' + # urls used for Reading / Tx Simulation / Tx Submit -- respectively. Change to others as needed. + rpcUrl_Read: 'https://worldchain-mainnet.g.alchemy.com/public' + rpcUrl_Sim: 'https://worldchain-mainnet.g.alchemy.com/public' + rpcUrl_Write: 'https://worldchain-mainnet.g.alchemy.com/public' + +TEST_ROUTES: + 480>10: + fromChainId: 480 + toChainId: 10 + testDistributionPercentage: 70 + 10>480: + fromChainId: 10 + toChainId: 480 + testDistributionPercentage: 15 + 8453>480: + fromChainId: 8453 + toChainId: 480 + testDistributionPercentage: 15 diff --git a/packages/rfq-loadtest/package.json b/packages/rfq-loadtest/package.json new file mode 100644 index 0000000000..c5640dc64c --- /dev/null +++ b/packages/rfq-loadtest/package.json @@ -0,0 +1,34 @@ +{ + "name": "@synapsecns/rfq-loadtest", + "version": "1.0.0", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "cp src/pyRepeater.py dist/ && tsc", + "lint": "eslint .", + "ci:lint": "eslint .", + "typecheck": "tsc", + "test:coverage": "echo 'No tests defined.'", + "build:go": " ", + "build:slither": " " + }, + "keywords": [], + "author": "", + "license": "ISC", + "private": "true", + "description": "", + "devDependencies": { + "@types/js-yaml": "^4.0.9", + "@types/node": "^22.7.5", + "@types/yargs": "^17.0.33", + "ts-node": "^10.9.2", + "typescript": "^5.6.3" + }, + "dependencies": { + "axios": "^1.7.7", + "js-yaml": "^4.1.0", + "viem": "^2.21.19", + "yargs": "^17.7.2" + } +} diff --git a/packages/rfq-loadtest/sql/ponderSummary.sql b/packages/rfq-loadtest/sql/ponderSummary.sql new file mode 100644 index 0000000000..0ce67b33ce --- /dev/null +++ b/packages/rfq-loadtest/sql/ponderSummary.sql @@ -0,0 +1,43 @@ + +-- run this on ponder index to get a summary of a test run. use WHERE params to point it at a particular test period. + +select to_timestamp(min(depositTs)) period_start, + to_timestamp(max(depositTs)) period_end, + max(depositTs) - min(depositTs) period_seconds, + round(count(1) * 1.00 / (max(depositTs) - min(depositTs)), 2) deposits_per_second, + round(count(1) * 1.00 / (max(depositTs) - min(depositTs)) * 86400, 0) deposits_per_day, + count(1) count_deposits, + count(case when proofSeconds is not null then 1 else null end) count_proofs, + count(case when claimSeconds is not null then 1 else null end) count_claims, + count(case when disputeId is not null then 1 else null end) count_disputes, + round(avg(relaySeconds), 2) relaySeconds_AVG, + max(relaySeconds) relaySeconds_MAX, + round(avg(proofSeconds), 2) proofSeconds_AVG, + max(proofSeconds) proofSeconds_MAX, + round(avg(claimSeconds), 2) claimSeconds_AVG, + max(claimSeconds) claimSeconds_MAX +from ( +-- this subquery can be executed by itself for detail data + select xdeposit."blockTimestamp" depositTs, + xdeposit."transactionId", + xrelay."blockTimestamp" - xdeposit."blockTimestamp" relaySeconds, + xproof."blockTimestamp" - xrelay."blockTimestamp" proofSeconds, + xclaim."blockTimestamp" - xproof."blockTimestamp" - 1800 claimSeconds, + xdispute.id disputeId, + xrelay.relayer + from "BridgeRequestEvents" xdeposit + left join "BridgeRelayedEvents" xrelay on + xdeposit."transactionId" = xrelay."transactionId" + left join "BridgeProofProvidedEvents" xproof on + xdeposit."transactionId" = xproof."transactionId" + left join "BridgeDepositClaimedEvents" xclaim on + xdeposit."transactionId" = xclaim."transactionId" + left join "BridgeProofDisputedEvents" xdispute on + xdeposit."transactionId" = xdispute."transactionId" + where xdeposit."originChainId" = 480 + and xdeposit."originAmount" <= 71000000000000 + + -- change these to point at a particular test period + and xdeposit."blockTimestamp" between 1728666774 and 1728667721 + ) sqData; + diff --git a/packages/rfq-loadtest/src/abi.ts b/packages/rfq-loadtest/src/abi.ts new file mode 100644 index 0000000000..d5345e3dc8 --- /dev/null +++ b/packages/rfq-loadtest/src/abi.ts @@ -0,0 +1,952 @@ +export const ABI = { + fastBridgeV1: [ + { + inputs: [{ internalType: 'address', name: '_owner', type: 'address' }], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { inputs: [], name: 'AccessControlBadConfirmation', type: 'error' }, + { + inputs: [ + { internalType: 'address', name: 'account', type: 'address' }, + { internalType: 'bytes32', name: 'neededRole', type: 'bytes32' }, + ], + name: 'AccessControlUnauthorizedAccount', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'target', type: 'address' }], + name: 'AddressEmptyCode', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'account', type: 'address' }], + name: 'AddressInsufficientBalance', + type: 'error', + }, + { inputs: [], name: 'AmountIncorrect', type: 'error' }, + { inputs: [], name: 'ChainIncorrect', type: 'error' }, + { inputs: [], name: 'DeadlineExceeded', type: 'error' }, + { inputs: [], name: 'DeadlineNotExceeded', type: 'error' }, + { inputs: [], name: 'DeadlineTooShort', type: 'error' }, + { inputs: [], name: 'DisputePeriodNotPassed', type: 'error' }, + { inputs: [], name: 'DisputePeriodPassed', type: 'error' }, + { inputs: [], name: 'FailedInnerCall', type: 'error' }, + { inputs: [], name: 'MsgValueIncorrect', type: 'error' }, + { + inputs: [{ internalType: 'address', name: 'token', type: 'address' }], + name: 'SafeERC20FailedOperation', + type: 'error', + }, + { inputs: [], name: 'SenderIncorrect', type: 'error' }, + { inputs: [], name: 'StatusIncorrect', type: 'error' }, + { inputs: [], name: 'TokenNotContract', type: 'error' }, + { inputs: [], name: 'TransactionRelayed', type: 'error' }, + { inputs: [], name: 'ZeroAddress', type: 'error' }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'bytes32', + name: 'transactionId', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'address', + name: 'relayer', + type: 'address', + }, + { indexed: true, internalType: 'address', name: 'to', type: 'address' }, + { + indexed: false, + internalType: 'address', + name: 'token', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'BridgeDepositClaimed', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'bytes32', + name: 'transactionId', + type: 'bytes32', + }, + { indexed: true, internalType: 'address', name: 'to', type: 'address' }, + { + indexed: false, + internalType: 'address', + name: 'token', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'BridgeDepositRefunded', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'bytes32', + name: 'transactionId', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'address', + name: 'relayer', + type: 'address', + }, + ], + name: 'BridgeProofDisputed', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'bytes32', + name: 'transactionId', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'address', + name: 'relayer', + type: 'address', + }, + { + indexed: false, + internalType: 'bytes32', + name: 'transactionHash', + type: 'bytes32', + }, + ], + name: 'BridgeProofProvided', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'bytes32', + name: 'transactionId', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'address', + name: 'relayer', + type: 'address', + }, + { indexed: true, internalType: 'address', name: 'to', type: 'address' }, + { + indexed: false, + internalType: 'uint32', + name: 'originChainId', + type: 'uint32', + }, + { + indexed: false, + internalType: 'address', + name: 'originToken', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'destToken', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'originAmount', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'destAmount', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'chainGasAmount', + type: 'uint256', + }, + ], + name: 'BridgeRelayed', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'bytes32', + name: 'transactionId', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + indexed: false, + internalType: 'bytes', + name: 'request', + type: 'bytes', + }, + { + indexed: false, + internalType: 'uint32', + name: 'destChainId', + type: 'uint32', + }, + { + indexed: false, + internalType: 'address', + name: 'originToken', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'destToken', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'originAmount', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'destAmount', + type: 'uint256', + }, + { + indexed: false, + internalType: 'bool', + name: 'sendChainGas', + type: 'bool', + }, + ], + name: 'BridgeRequested', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint256', + name: 'oldChainGasAmount', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'newChainGasAmount', + type: 'uint256', + }, + ], + name: 'ChainGasAmountUpdated', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint256', + name: 'oldFeeRate', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'newFeeRate', + type: 'uint256', + }, + ], + name: 'FeeRateUpdated', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'token', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'recipient', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'FeesSwept', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'bytes32', + name: 'role', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'bytes32', + name: 'previousAdminRole', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'bytes32', + name: 'newAdminRole', + type: 'bytes32', + }, + ], + name: 'RoleAdminChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'bytes32', + name: 'role', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'address', + name: 'account', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'sender', + type: 'address', + }, + ], + name: 'RoleGranted', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'bytes32', + name: 'role', + type: 'bytes32', + }, + { + indexed: true, + internalType: 'address', + name: 'account', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'sender', + type: 'address', + }, + ], + name: 'RoleRevoked', + type: 'event', + }, + { + inputs: [], + name: 'DEFAULT_ADMIN_ROLE', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'DISPUTE_PERIOD', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'FEE_BPS', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'FEE_RATE_MAX', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'GOVERNOR_ROLE', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'GUARD_ROLE', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'MIN_DEADLINE_PERIOD', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'REFUNDER_ROLE', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'REFUND_DELAY', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'RELAYER_ROLE', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + components: [ + { internalType: 'uint32', name: 'dstChainId', type: 'uint32' }, + { internalType: 'address', name: 'sender', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'address', name: 'originToken', type: 'address' }, + { internalType: 'address', name: 'destToken', type: 'address' }, + { internalType: 'uint256', name: 'originAmount', type: 'uint256' }, + { internalType: 'uint256', name: 'destAmount', type: 'uint256' }, + { internalType: 'bool', name: 'sendChainGas', type: 'bool' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + ], + internalType: 'struct IFastBridge.BridgeParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'bridge', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + name: 'bridgeProofs', + outputs: [ + { internalType: 'uint96', name: 'timestamp', type: 'uint96' }, + { internalType: 'address', name: 'relayer', type: 'address' }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + name: 'bridgeRelays', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + name: 'bridgeStatuses', + outputs: [ + { + internalType: 'enum FastBridge.BridgeStatus', + name: '', + type: 'uint8', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes32', name: 'transactionId', type: 'bytes32' }, + { internalType: 'address', name: 'relayer', type: 'address' }, + ], + name: 'canClaim', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'chainGasAmount', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes', name: 'request', type: 'bytes' }, + { internalType: 'address', name: 'to', type: 'address' }, + ], + name: 'claim', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'deployBlock', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes32', name: 'transactionId', type: 'bytes32' }, + ], + name: 'dispute', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes', name: 'request', type: 'bytes' }], + name: 'getBridgeTransaction', + outputs: [ + { + components: [ + { internalType: 'uint32', name: 'originChainId', type: 'uint32' }, + { internalType: 'uint32', name: 'destChainId', type: 'uint32' }, + { internalType: 'address', name: 'originSender', type: 'address' }, + { internalType: 'address', name: 'destRecipient', type: 'address' }, + { internalType: 'address', name: 'originToken', type: 'address' }, + { internalType: 'address', name: 'destToken', type: 'address' }, + { internalType: 'uint256', name: 'originAmount', type: 'uint256' }, + { internalType: 'uint256', name: 'destAmount', type: 'uint256' }, + { + internalType: 'uint256', + name: 'originFeeAmount', + type: 'uint256', + }, + { internalType: 'bool', name: 'sendChainGas', type: 'bool' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'uint256', name: 'nonce', type: 'uint256' }, + ], + internalType: 'struct IFastBridge.BridgeTransaction', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes32', name: 'role', type: 'bytes32' }], + name: 'getRoleAdmin', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes32', name: 'role', type: 'bytes32' }, + { internalType: 'uint256', name: 'index', type: 'uint256' }, + ], + name: 'getRoleMember', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes32', name: 'role', type: 'bytes32' }], + name: 'getRoleMemberCount', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes32', name: 'role', type: 'bytes32' }, + { internalType: 'address', name: 'account', type: 'address' }, + ], + name: 'grantRole', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes32', name: 'role', type: 'bytes32' }, + { internalType: 'address', name: 'account', type: 'address' }, + ], + name: 'hasRole', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'nonce', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'protocolFeeRate', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: '', type: 'address' }], + name: 'protocolFees', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes', name: 'request', type: 'bytes' }, + { internalType: 'bytes32', name: 'destTxHash', type: 'bytes32' }, + ], + name: 'prove', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes', name: 'request', type: 'bytes' }], + name: 'refund', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes', name: 'request', type: 'bytes' }], + name: 'relay', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes32', name: 'role', type: 'bytes32' }, + { + internalType: 'address', + name: 'callerConfirmation', + type: 'address', + }, + ], + name: 'renounceRole', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes32', name: 'role', type: 'bytes32' }, + { internalType: 'address', name: 'account', type: 'address' }, + ], + name: 'revokeRole', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: 'newChainGasAmount', type: 'uint256' }, + ], + name: 'setChainGasAmount', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: 'newFeeRate', type: 'uint256' }, + ], + name: 'setProtocolFeeRate', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes4', name: 'interfaceId', type: 'bytes4' }], + name: 'supportsInterface', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'token', type: 'address' }, + { internalType: 'address', name: 'recipient', type: 'address' }, + ], + name: 'sweepProtocolFees', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + ], + + fastRouterV2: [ + { + inputs: [{ internalType: 'address', name: 'owner_', type: 'address' }], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { inputs: [], name: 'DeadlineExceeded', type: 'error' }, + { + inputs: [], + name: 'FastBridgeRouterV2__OriginSenderNotSpecified', + type: 'error', + }, + { inputs: [], name: 'InsufficientOutputAmount', type: 'error' }, + { inputs: [], name: 'MsgValueIncorrect', type: 'error' }, + { inputs: [], name: 'PoolNotFound', type: 'error' }, + { inputs: [], name: 'TokenAddressMismatch', type: 'error' }, + { inputs: [], name: 'TokenNotContract', type: 'error' }, + { inputs: [], name: 'TokenNotETH', type: 'error' }, + { inputs: [], name: 'TokensIdentical', type: 'error' }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'newFastBridge', + type: 'address', + }, + ], + name: 'FastBridgeSet', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'previousOwner', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'newOwner', + type: 'address', + }, + ], + name: 'OwnershipTransferred', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'newSwapQuoter', + type: 'address', + }, + ], + name: 'SwapQuoterSet', + type: 'event', + }, + { + inputs: [], + name: 'GAS_REBATE_FLAG', + outputs: [{ internalType: 'bytes1', name: '', type: 'bytes1' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'recipient', type: 'address' }, + { internalType: 'address', name: 'tokenIn', type: 'address' }, + { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, + { internalType: 'address', name: 'tokenOut', type: 'address' }, + { internalType: 'bytes', name: 'rawParams', type: 'bytes' }, + ], + name: 'adapterSwap', + outputs: [ + { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'recipient', type: 'address' }, + { internalType: 'uint256', name: 'chainId', type: 'uint256' }, + { internalType: 'address', name: 'token', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { + components: [ + { internalType: 'address', name: 'routerAdapter', type: 'address' }, + { internalType: 'address', name: 'tokenOut', type: 'address' }, + { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'bytes', name: 'rawParams', type: 'bytes' }, + ], + internalType: 'struct SwapQuery', + name: 'originQuery', + type: 'tuple', + }, + { + components: [ + { internalType: 'address', name: 'routerAdapter', type: 'address' }, + { internalType: 'address', name: 'tokenOut', type: 'address' }, + { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'bytes', name: 'rawParams', type: 'bytes' }, + ], + internalType: 'struct SwapQuery', + name: 'destQuery', + type: 'tuple', + }, + ], + name: 'bridge', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [], + name: 'fastBridge', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'tokenIn', type: 'address' }, + { internalType: 'address[]', name: 'rfqTokens', type: 'address[]' }, + { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, + ], + name: 'getOriginAmountOut', + outputs: [ + { + components: [ + { internalType: 'address', name: 'routerAdapter', type: 'address' }, + { internalType: 'address', name: 'tokenOut', type: 'address' }, + { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'bytes', name: 'rawParams', type: 'bytes' }, + ], + internalType: 'struct SwapQuery[]', + name: 'originQueries', + type: 'tuple[]', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'owner', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'renounceOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'fastBridge_', type: 'address' }, + ], + name: 'setFastBridge', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'swapQuoter_', type: 'address' }, + ], + name: 'setSwapQuoter', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'swapQuoter', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'newOwner', type: 'address' }], + name: 'transferOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { stateMutability: 'payable', type: 'receive' }, + ], +} diff --git a/packages/rfq-loadtest/src/index.ts b/packages/rfq-loadtest/src/index.ts new file mode 100644 index 0000000000..c064a36022 --- /dev/null +++ b/packages/rfq-loadtest/src/index.ts @@ -0,0 +1,496 @@ +import fs from 'fs/promises' + +import * as viemChains from 'viem/chains' +import { privateKeyToAccount } from 'viem/accounts' +import { + createPublicClient, + createWalletClient, + formatUnits, + http, + parseUnits, + publicActions, + PublicClient, + WalletClient, +} from 'viem' +import yaml from 'js-yaml' +import yargs from 'yargs' +import { hideBin } from 'yargs/helpers' +import axios from 'axios' +import { createNonceManager, jsonRpc } from 'viem/nonce' + +import { ABI } from './abi.js' +import { delay, print, getRandomInt } from './utils.js' + +const argv = await yargs(hideBin(process.argv)) + .option('configFile', { + alias: 'c', + type: 'string', + description: 'Path to the config file', + demandOption: true, + }) + .option('pKeyIndex', { + alias: 'p', + type: 'number', + description: 'Index of the private key', + demandOption: true, + }) + .help().argv + +const configFilePath = argv.configFile +const configFileContent = await fs.readFile(configFilePath, 'utf-8') + +let config: any +try { + config = yaml.load(configFileContent) as object + + if (typeof config !== 'object' || config === null) { + throw new Error() + } + + if ( + typeof config.VOLLEY_MILLISECONDS_BETWEEN !== 'number' || + typeof config.VOLLEY_MIN_COUNT !== 'number' || + typeof config.VOLLEY_MAX_COUNT !== 'number' + ) { + throw new Error('Invalid configuration values for volley settings') + } + + if (typeof config.CHAINS !== 'object' || config.CHAINS === null) { + throw new Error('Invalid configuration for CHAINS') + } + + if (typeof config.TEST_ROUTES !== 'object' || config.TEST_ROUTES === null) { + throw new Error('Invalid configuration for TEST_ROUTES') + } + + if (typeof config.TEST_BRIDGE_AMOUNT_UNITS !== 'number') { + throw new Error('Invalid configuration for TEST_BRIDGE_AMOUNT_UNITS') + } + if (typeof config.MINIMUM_GAS_UNITS !== 'number') { + throw new Error('Invalid configuration for MINIMUM_GAS_UNITS') + } + if (typeof config.REBALANCE_TO_UNITS !== 'number') { + throw new Error('Invalid configuration for REBALANCE_TO_UNITS') + } + + Object.entries(config.TEST_ROUTES).forEach( + ([route, details]: [string, any]) => { + if (typeof details !== 'object' || details === null) { + throw new Error(`Invalid configuration for route: ${route}`) + } + if ( + typeof details.fromChainId !== 'number' || + typeof details.toChainId !== 'number' || + typeof details.testDistributionPercentage !== 'number' + ) { + throw new Error(`Invalid configuration values for route: ${route}`) + } + } + ) +} catch (error: any) { + throw new Error( + `Failed to parse ${configFilePath}. Check your syntax, structure, data, and for duplicates. \n${error.message}` + ) +} + +const privateKeyIndex = argv.pKeyIndex +if (typeof privateKeyIndex !== 'number' || privateKeyIndex < 1) { + throw new Error('pKeyIndex must be a positive integer') +} + +const privateKeyName = `PRIVATE_KEY_${privateKeyIndex}` +const privateKey: `0x${string}` = config[privateKeyName] as `0x${string}` + +if (!privateKey) { + throw new Error(`${privateKeyName} is not defined in the config file`) +} + +// construct enriched versions of viem chain objects ("vChains") based on what was supplied in config file +const vChains: any = {} +Object.entries(config.CHAINS).forEach( + ([chainId, chainConfig]: [string, any]) => { + const viemChain = Object.values(viemChains).find( + (chain) => chain.id === parseInt(chainId, 10) + ) + if (!viemChain) { + throw new Error( + `No viem chain config found for chain ID ${chainId}. Bump viem version or add manually` + ) + } + + vChains[chainId] = { + ...viemChain, + ...chainConfig, + vCliRead: {} as PublicClient, + vCliSim: {} as WalletClient, + vCliWrite: {} as WalletClient, + } + } +) + +const nonceManager = createNonceManager({ + source: jsonRpc(), +}) + +const walletAccount = privateKeyToAccount(privateKey, { nonceManager }) + +print(`Using ${privateKeyName}: ${walletAccount.address}`) + +Object.keys(vChains).forEach((chainId: string) => { + const chain = vChains[chainId] + + chain.vCliRead = createPublicClient({ + chain, + transport: http(chain.rpcUrl_Read), + }) as PublicClient + + chain.vCliSim = createWalletClient({ + chain, + transport: http(chain.rpcUrl_Sim), + }).extend(publicActions) + + chain.vCliWrite = createWalletClient({ + chain, + transport: http(chain.rpcUrl_Write), + }).extend(publicActions) + + Promise.all([ + chain.vCliRead.readContract({ + address: chain.FastRouterAddr, + abi: ABI.fastRouterV2, + functionName: 'fastBridge', + }), + // not just used to report block height. also serves as connectivity test for all three clients. + chain.vCliRead.getBlockNumber(), + chain.vCliSim.getBlockNumber(), + chain.vCliWrite.getBlockNumber(), + ]).then( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ([fastBridgeAddr, blockNumber_Read, blockNumber_Sim, blockNumber_Write]: [ + string, + bigint, + bigint, + bigint + ]) => { + print( + `Connected to chain ID ${chainId + .toString() + .padStart(7)}. FastBridge at: ${fastBridgeAddr.slice( + 0, + 6 + )}... Current block height: ${blockNumber_Read}` + ) + } + ) +}) + +let cachedResponseRFQ: any + +let sendCounter = 0 + +let lastAction: string = 'none' + +const testBridgeAmountUnits = config.TEST_BRIDGE_AMOUNT_UNITS + +mainFlow() + +async function mainFlow() { + await delay(1500) + + while (!walletAccount.address) { + print(`%ts Awaiting Initialization...`) + await delay(5000) + } + + checkBals() + + looper_getRequestParams() + + await delay(2500) + + while (!cachedResponseRFQ) { + print(`%ts Awaiting cached RFQ API response to populate...`) + await delay(5000) + } + + bridgeLooper() +} + +async function checkBals() { + for (;;) { + await Promise.all( + Object.keys(vChains).map(async (chainId: string) => { + const chain = vChains[chainId] + try { + const balance = await chain.vCliRead.getBalance({ + address: walletAccount.address, + }) + chain.balanceRaw = balance + chain.balanceUnits = formatUnits(balance, 18) + } catch (error: any) { + print( + `Error fetching balance for chain ID ${chainId}: ${error.message}` + ) + } + }) + ) + + await delay(15_000) + } +} + +const minGasUnits = config.MINIMUM_GAS_UNITS +const rebalToUnits = config.REBALANCE_TO_UNITS +async function bridgeLooper() { + + let retryCount = 0 + + for (;;) { + // Find the chain with the lowest balance below our minimum gas -- if any + const rebalToChain: any = Object.values(vChains).find( + (chain: any) => chain.balanceUnits < minGasUnits + ) + + if (rebalToChain) { + const rebalFromChain: any = Object.values(vChains).reduce( + (prev: any, current: any) => { + return prev.balanceUnits > current.balanceUnits ? prev : current + } + ) + + const rebalLabel = `%ts Rebal: ${rebalFromChain.id} > ${rebalToChain.id}` + + print(rebalLabel) + + // avoid repeating rebal actions. just loop until it lands on-chain. + if (lastAction === `rebal${rebalFromChain.id}>${rebalToChain.id}`) { + print( + `${rebalLabel} Last action was identical (${lastAction}). Not repeating. Re-evaluating momentarily...` + ) + + if (retryCount > 5) { + // abort after X attempts - if running in repeater mode this will effectively re-send the rebal tx if it is still needed + print(`${rebalLabel} Max retries. Exiting process...`) + await delay(1500) + process.exit() + } + + await delay(7500) + retryCount++ + continue + } + + retryCount=0 + + // leave rebalFrom chain with X units + const rebalAmount = rebalToUnits - rebalToChain.balanceUnits + + if (rebalFromChain.balanceUnits < rebalToUnits * 1.1) { + // if we hit this point, it indicates the wallet has no funds left to keep playing. hang process. + print( + `${rebalLabel} - Insuff Funds on From Chain ${rebalFromChain.balanceUnits}. Ending tests.` + ) + await delay(60_000) + return + } + + await sendBridge( + rebalFromChain, + rebalToChain, + Number(rebalAmount.toFixed(18)), + false, + rebalLabel + ) + + lastAction = `rebal${rebalFromChain.id}>${rebalToChain.id}` + + await delay(config.VOLLEY_MILLISECONDS_BETWEEN) + continue + } + + let fromChain: any + let toChain: any + + const totalPercentage: number = Object.values(config.TEST_ROUTES).reduce( + (acc: number, route: any) => acc + route.testDistributionPercentage, + 0 + ) + const randomizer: number = getRandomInt(1, totalPercentage) + let cumulative = 0 + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + for (const [route, details] of Object.entries(config.TEST_ROUTES) as [ + string, + any + ][]) { + cumulative += details.testDistributionPercentage + if (randomizer <= cumulative) { + fromChain = vChains[`${details.fromChainId}`] + toChain = vChains[`${details.toChainId}`] + break + } + } + + const countToSend = getRandomInt( + config.VOLLEY_MIN_COUNT, + config.VOLLEY_MAX_COUNT + ) + const printLabel = `%ts Batch${(sendCounter + countToSend) + .toString() + .padStart(5, '0')} of ${countToSend} : ${fromChain.id + .toString() + .padStart(7)} >> ${toChain.id.toString().padEnd(7)}` + + for (let i = 0; i < countToSend; i++) { + // sendCounter is applied as a tag on the amount just for sloppy tracking purposes. not actually important. + sendBridge( + fromChain, + toChain, + Number( + (testBridgeAmountUnits + sendCounter / 100000000000).toFixed(18) + ), + true, + printLabel + ) + sendCounter++ + await delay(50) + } + + lastAction = 'testVolley' + await delay(config.VOLLEY_MILLISECONDS_BETWEEN) + } +} + +async function getRequestParams( + fromChain: any, + toChain: any, + sendAmountUnits: number +) { + // 480 is not supported currently on the API - using Opti/Base as proxies. Can be improved later as needed. + if (toChain.id === 480) { + toChain = fromChain.id === 8453 ? vChains['10'] : vChains['8453'] + } + if (fromChain.id === 480) { + fromChain = toChain.id === 8453 ? vChains['10'] : vChains['8453'] + } + + const requestURL = `https://api.synapseprotocol.com/bridge?fromChain=${ + fromChain.id + }&toChain=${ + toChain.id + }&fromToken=${'0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'}&toToken=${'0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'}&amount=${sendAmountUnits}&destAddress=${ + walletAccount.address + }` + + let responseRFQ: any + let response: any + try { + response = await axios.request({ + url: requestURL, + }) + + if ((response.data?.length ?? 0) === 0) { + throw new Error(`No data returned from api`) + } + + responseRFQ = Array.isArray(response.data) + ? response.data.find( + (item: any) => item.bridgeModuleName === 'SynapseRFQ' + ) + : null + if (!responseRFQ) { + throw new Error(`No RFQ response returned from api`) + } + } catch (error: any) { + throw new Error( + `RFQ Api Fail: ${error.message.substr(0, 50)} -- ${requestURL}` + ) + } + + return responseRFQ +} + +async function looper_getRequestParams() { + for (;;) { + // in future iteration, this could be improved to dynamically pull a response for each route that is involved w/ testing. + // for now, all tests just use a cached route btwn two OP stacks as proxies for Worldchain tests -- because this is close enough. + cachedResponseRFQ = await getRequestParams( + vChains['8453'], + vChains['10'], + testBridgeAmountUnits + ) + + await delay(10_000) + } +} + +async function sendBridge( + fromChain: any, + toChain: any, + sendAmountUnits: number, + useCachedRequest: boolean, + printLabel: string +) { + const sendAmountRaw = parseUnits(sendAmountUnits.toString(), 18) + + printLabel = printLabel + ` ${sendAmountUnits} ETH` + + const _responseRFQ = useCachedRequest + ? cachedResponseRFQ + : await getRequestParams(fromChain, toChain, sendAmountUnits) + + const contractCall: any = { + address: fromChain.FastRouterAddr as `0x${string}`, + abi: ABI.fastRouterV2, + functionName: 'bridge', + account: walletAccount, + chain: fromChain, + args: [ + walletAccount.address, //recipient + toChain.id, // chainId + '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // token + sendAmountRaw, // amount + [ + //originQuery + '0x0000000000000000000000000000000000000000', //routerAdapter + _responseRFQ.originQuery.tokenOut, //tokenOut + sendAmountRaw, //minAmountOut + BigInt(_responseRFQ.originQuery.deadline.hex), //deadline + _responseRFQ.originQuery.rawParams, //rawParms + ], + [ + //destQuery + '0x0000000000000000000000000000000000000000', //routerAdapter + _responseRFQ.destQuery.tokenOut, //tokenOut + BigInt(_responseRFQ.destQuery.minAmountOut.hex), //minAmountOut + BigInt(_responseRFQ.destQuery.deadline.hex), //deadline + _responseRFQ.destQuery.rawParams, //rawParms + ], + ], + value: sendAmountRaw, + } + + let estGasUnits + + try { + //@ts-ignore + estGasUnits = await fromChain.vCliSim.estimateContractGas(contractCall) + } catch (error: any) { + throw new Error(`${printLabel} Bridge Sim error: ${error.message}`) + } + + if (estGasUnits <= 50000n) { + throw new Error(`${printLabel} estimated gas units too low. possible error`) + } + + contractCall.gas = Math.floor(Number(estGasUnits) * 1.3) + + let txHash + try { + txHash = await fromChain.vCliWrite.writeContract(contractCall) + } catch (error: any) { + throw new Error(`${printLabel} Send failed: ${error.message}`) + } + + print(`${printLabel} Submitted ${txHash}`) +} diff --git a/packages/rfq-loadtest/src/pyRepeater.py b/packages/rfq-loadtest/src/pyRepeater.py new file mode 100644 index 0000000000..1094c43cd0 --- /dev/null +++ b/packages/rfq-loadtest/src/pyRepeater.py @@ -0,0 +1,11 @@ +import time +import subprocess +import sys +from datetime import datetime + +callStatement = sys.argv[1] + +while 1==1: + subprocess.call(f"{callStatement}", shell=True) + print (f"{datetime.now()} - Restarting...") + time.sleep(1) \ No newline at end of file diff --git a/packages/rfq-loadtest/src/utils.ts b/packages/rfq-loadtest/src/utils.ts new file mode 100644 index 0000000000..0785c8dcdd --- /dev/null +++ b/packages/rfq-loadtest/src/utils.ts @@ -0,0 +1,34 @@ +export function delay(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)) +} + +export function tStamp(startTimeStamp = 0) { + const timeCur = new Date().toISOString().replace('T', ' ').replace('Z', '') + + const timeDiff = + startTimeStamp > 0 + ? ` +${(Date.now() - startTimeStamp).toString().padStart(5)}ms` + : '' + + return `${timeCur}${timeDiff} - ` +} + +export function print(...outputs: any[]) { + outputs = outputs.map((output: any) => { + if (typeof output == 'string') { + // Replace %ts with formatted timestamp + output = output.replaceAll('%ts', tStamp()) + } + return output + }) + + console.log(...outputs) +} + +export function getRandomInt(min: number, max: number) { + if (min > max) { + // fix mistake inputs + ;[min, max] = [max, min] + } + return Math.floor(Math.random() * (max - min + 1)) + min +} diff --git a/packages/rfq-loadtest/tsconfig.json b/packages/rfq-loadtest/tsconfig.json new file mode 100644 index 0000000000..bf8c0320ea --- /dev/null +++ b/packages/rfq-loadtest/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "esnext", + "moduleResolution": "node", + "sourceMap": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 61c7578a54..bbf0529519 100644 --- a/yarn.lock +++ b/yarn.lock @@ -55,7 +55,7 @@ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== -"@adraffy/ens-normalize@^1.8.8": +"@adraffy/ens-normalize@1.11.0", "@adraffy/ens-normalize@^1.8.8": version "1.11.0" resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz#42cc67c5baa407ac25059fcd7d405cc5ecdb0c33" integrity sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg== @@ -6007,7 +6007,7 @@ dependencies: "@noble/hashes" "1.4.0" -"@noble/curves@^1.4.0": +"@noble/curves@1.6.0", "@noble/curves@^1.4.0", "@noble/curves@~1.6.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.6.0.tgz#be5296ebcd5a1730fccea4786d420f87abfeb40b" integrity sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ== @@ -7122,7 +7122,7 @@ resolved "https://registry.yarnpkg.com/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.22.2.tgz#d4ff9972e58f9344fc95f8d41b2ec6517baa8e79" integrity sha512-Y0yAxRaB98LFp2Dm+ACZqBSdAmI3FlpH/LjxOZ94g/ouuDJecSq0iR26XZ5QDuEL8Rf+L4jBJaoDC08CD0KkJw== -"@scure/base@^1.1.3", "@scure/base@~1.1.0", "@scure/base@~1.1.2", "@scure/base@~1.1.6", "@scure/base@~1.1.8": +"@scure/base@^1.1.3", "@scure/base@~1.1.0", "@scure/base@~1.1.2", "@scure/base@~1.1.6", "@scure/base@~1.1.7", "@scure/base@~1.1.8": version "1.1.9" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.9.tgz#e5e142fbbfe251091f9c5f1dd4c834ac04c3dbd1" integrity sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg== @@ -7154,6 +7154,15 @@ "@noble/hashes" "~1.4.0" "@scure/base" "~1.1.6" +"@scure/bip32@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.5.0.tgz#dd4a2e1b8a9da60e012e776d954c4186db6328e6" + integrity sha512-8EnFYkqEQdnkuGBVpCzKxyIwDCBLDVj3oiX0EKUFre/tOjL/Hqba1D6n/8RcmaQy4f95qQFrO2A8Sr6ybh4NRw== + dependencies: + "@noble/curves" "~1.6.0" + "@noble/hashes" "~1.5.0" + "@scure/base" "~1.1.7" + "@scure/bip39@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" @@ -9324,7 +9333,7 @@ jest-diff "^25.2.1" pretty-format "^25.2.1" -"@types/js-yaml@^4.0.0": +"@types/js-yaml@^4.0.0", "@types/js-yaml@^4.0.9": version "4.0.9" resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2" integrity sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg== @@ -9469,6 +9478,13 @@ dependencies: undici-types "~6.19.2" +"@types/node@^22.7.5": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" + "@types/normalize-package-data@^2.4.0": version "2.4.4" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" @@ -9859,7 +9875,7 @@ dependencies: "@types/yargs-parser" "*" -"@types/yargs@^17.0.8": +"@types/yargs@^17.0.33", "@types/yargs@^17.0.8": version "17.0.33" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== @@ -11090,6 +11106,11 @@ abitype@1.0.5: resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.5.tgz#29d0daa3eea867ca90f7e4123144c1d1270774b6" integrity sha512-YzDhti7cjlfaBhHutMaboYB21Ha3rXR9QTkNJFzYC4kC8YclaiwPBBBJY8ejFdu2wnJeZCVZSMlQJ7fi8S6hsw== +abitype@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.6.tgz#76410903e1d88e34f1362746e2d407513c38565b" + integrity sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A== + abitype@^0.10.2: version "0.10.3" resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.10.3.tgz#27ce7a7cdb9a80ccd732a3f3cf1ce6ff05266fce" @@ -21583,6 +21604,11 @@ isows@1.0.4: resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.4.tgz#810cd0d90cc4995c26395d2aa4cfa4037ebdf061" integrity sha512-hEzjY+x9u9hPmBom9IIAqdJCwNLax+xrPb51vEPpERoFlIxgmZcHzsT5jKG06nvInKOBGvReAVz80Umed5CczQ== +isows@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.6.tgz#0da29d706fa51551c663c627ace42769850f86e7" + integrity sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw== + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -33985,6 +34011,11 @@ typescript@^5.0.4, typescript@^5.2.2, typescript@^5.3.2, typescript@^5.3.3, type resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.2.tgz#d1de67b6bef77c41823f822df8f0b3bcff60a5a0" integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw== +typescript@^5.6.3: + version "5.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" + integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== + typescript@~5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" @@ -35024,6 +35055,21 @@ viem@^2.1.1, viem@^2.13.6, viem@^2.21.6: webauthn-p256 "0.0.5" ws "8.17.1" +viem@^2.21.19: + version "2.21.25" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.21.25.tgz#5e4a7c6a8543396f67ef221ea5d2226321f000b8" + integrity sha512-fQbFLVW5RjC1MwjelmzzDygmc2qMfY17NruAIIdYeiB8diQfhqsczU5zdGw/jTbmNXbKoYnSdgqMb8MFZcbZ1w== + dependencies: + "@adraffy/ens-normalize" "1.11.0" + "@noble/curves" "1.6.0" + "@noble/hashes" "1.5.0" + "@scure/bip32" "1.5.0" + "@scure/bip39" "1.4.0" + abitype "1.0.6" + isows "1.0.6" + webauthn-p256 "0.0.10" + ws "8.18.0" + vite-node@^1.0.2: version "1.6.0" resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.6.0.tgz#2c7e61129bfecc759478fa592754fd9704aaba7f" @@ -35891,6 +35937,14 @@ web3@1.7.4: web3-shh "1.7.4" web3-utils "1.7.4" +webauthn-p256@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/webauthn-p256/-/webauthn-p256-0.0.10.tgz#877e75abe8348d3e14485932968edf3325fd2fdd" + integrity sha512-EeYD+gmIT80YkSIDb2iWq0lq2zbHo1CxHlQTeJ+KkCILWpVy3zASH3ByD4bopzfk0uCwXxLqKGLqp2W4O28VFA== + dependencies: + "@noble/curves" "^1.4.0" + "@noble/hashes" "^1.4.0" + webauthn-p256@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/webauthn-p256/-/webauthn-p256-0.0.5.tgz#0baebd2ba8a414b21cc09c0d40f9dd0be96a06bd" @@ -36544,6 +36598,11 @@ ws@8.17.1, ws@~8.17.1: resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== +ws@8.18.0, ws@^8.12.0, ws@^8.13.0, ws@^8.17.1, ws@^8.2.3: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + ws@^3.0.0: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" @@ -36558,11 +36617,6 @@ ws@^7.0.0, ws@^7.3.1, ws@^7.4.6, ws@^7.5.1: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== -ws@^8.12.0, ws@^8.13.0, ws@^8.17.1, ws@^8.2.3: - version "8.18.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" - integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== - x-default-browser@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/x-default-browser/-/x-default-browser-0.4.0.tgz#70cf0da85da7c0ab5cb0f15a897f2322a6bdd481" From ed60f1793860842542806a6a260a13f8d4712fd9 Mon Sep 17 00:00:00 2001 From: parodime Date: Tue, 15 Oct 2024 16:34:14 +0000 Subject: [PATCH 41/47] Publish - @synapsecns/bridge-docs@0.4.4 - @synapsecns/rfq-loadtest@1.0.1 --- docs/bridge/CHANGELOG.md | 8 ++++++++ docs/bridge/package.json | 2 +- packages/rfq-loadtest/CHANGELOG.md | 8 ++++++++ packages/rfq-loadtest/package.json | 2 +- 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 packages/rfq-loadtest/CHANGELOG.md diff --git a/docs/bridge/CHANGELOG.md b/docs/bridge/CHANGELOG.md index 6aae6f9de8..c692d12f9d 100644 --- a/docs/bridge/CHANGELOG.md +++ b/docs/bridge/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.4.4](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.4.3...@synapsecns/bridge-docs@0.4.4) (2024-10-15) + +**Note:** Version bump only for package @synapsecns/bridge-docs + + + + + ## [0.4.3](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.4.2...@synapsecns/bridge-docs@0.4.3) (2024-10-15) **Note:** Version bump only for package @synapsecns/bridge-docs diff --git a/docs/bridge/package.json b/docs/bridge/package.json index f3bb4e55a7..7b01af0b92 100644 --- a/docs/bridge/package.json +++ b/docs/bridge/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/bridge-docs", - "version": "0.4.3", + "version": "0.4.4", "private": true, "scripts": { "docusaurus": "docusaurus", diff --git a/packages/rfq-loadtest/CHANGELOG.md b/packages/rfq-loadtest/CHANGELOG.md new file mode 100644 index 0000000000..23b23875d4 --- /dev/null +++ b/packages/rfq-loadtest/CHANGELOG.md @@ -0,0 +1,8 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## 1.0.1 (2024-10-15) + +**Note:** Version bump only for package @synapsecns/rfq-loadtest diff --git a/packages/rfq-loadtest/package.json b/packages/rfq-loadtest/package.json index c5640dc64c..763a876e7a 100644 --- a/packages/rfq-loadtest/package.json +++ b/packages/rfq-loadtest/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/rfq-loadtest", - "version": "1.0.0", + "version": "1.0.1", "main": "index.js", "type": "module", "scripts": { From 31a3ce9f1a90d47425dae6ef969b28de3895a6aa Mon Sep 17 00:00:00 2001 From: abtestingalpha <104046418+abtestingalpha@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:48:22 -0400 Subject: [PATCH 42/47] feat(rest-api): Primary RPCs get omnirpc (#3294) * Primary RPCs get omnirpc --- packages/rest-api/.env.example | 1 + packages/rest-api/package.json | 1 + packages/rest-api/src/constants/chains.ts | 89 +-- .../rest-api/src/services/synapseService.ts | 3 +- packages/rest-api/src/utils/getOmniRpcUrl.ts | 10 + yarn.lock | 643 +++++++++++++++++- 6 files changed, 689 insertions(+), 58 deletions(-) create mode 100644 packages/rest-api/.env.example create mode 100644 packages/rest-api/src/utils/getOmniRpcUrl.ts diff --git a/packages/rest-api/.env.example b/packages/rest-api/.env.example new file mode 100644 index 0000000000..8bb7766569 --- /dev/null +++ b/packages/rest-api/.env.example @@ -0,0 +1 @@ +OMNIRPC_BASE_URL= \ No newline at end of file diff --git a/packages/rest-api/package.json b/packages/rest-api/package.json index 38b029d3d3..cc3dc43fa6 100644 --- a/packages/rest-api/package.json +++ b/packages/rest-api/package.json @@ -24,6 +24,7 @@ "@ethersproject/units": "5.7.0", "@synapsecns/sdk-router": "^0.11.4", "bignumber": "^1.1.0", + "dotenv": "^16.4.5", "ethers": "5.7.2", "express": "^4.18.2", "express-validator": "^7.2.0", diff --git a/packages/rest-api/src/constants/chains.ts b/packages/rest-api/src/constants/chains.ts index dcc4c2502b..521698e789 100644 --- a/packages/rest-api/src/constants/chains.ts +++ b/packages/rest-api/src/constants/chains.ts @@ -1,13 +1,14 @@ import _ from 'lodash' import { Chain } from '../types' +import { getOmniRpcUrl } from '../utils/getOmniRpcUrl' export const ETHEREUM: Chain = { id: 1, name: 'Ethereum', rpcUrls: { - primary: 'https://ethereum.blockpi.network/v1/rpc/public', - fallback: 'https://rpc.ankr.com/eth', + primary: getOmniRpcUrl(1), + fallback: 'https://ethereum.blockpi.network/v1/rpc/public', }, explorerUrl: 'https://etherscan.com', explorerName: 'Etherscan', @@ -27,8 +28,8 @@ export const ARBITRUM: Chain = { id: 42161, name: 'Arbitrum', rpcUrls: { - primary: 'https://arbitrum.blockpi.network/v1/rpc/public', - fallback: 'https://arb1.arbitrum.io/rpc', + primary: getOmniRpcUrl(42161), + fallback: 'https://arbitrum.blockpi.network/v1/rpc/public', }, explorerUrl: 'https://arbiscan.io', explorerName: 'Arbiscan', @@ -48,8 +49,8 @@ export const BNBCHAIN: Chain = { id: 56, name: 'BNB Chain', rpcUrls: { - primary: 'https://bsc-dataseed1.ninicoin.io/', - fallback: 'https://bsc-dataseed2.ninicoin.io', + primary: getOmniRpcUrl(56), + fallback: 'https://bsc-dataseed1.ninicoin.io/', }, explorerUrl: 'https://bscscan.com', explorerName: 'BscScan', @@ -69,8 +70,8 @@ export const AVALANCHE: Chain = { id: 43114, name: 'Avalanche', rpcUrls: { - primary: 'https://api.avax.network/ext/bc/C/rpc', - fallback: 'https://1rpc.io/avax/c', + primary: getOmniRpcUrl(43114), + fallback: 'https://api.avax.network/ext/bc/C/rpc', }, explorerUrl: 'https://snowtrace.io/', explorerName: 'Snowtrace', @@ -90,8 +91,8 @@ export const CANTO: Chain = { id: 7700, name: 'Canto', rpcUrls: { - primary: 'https://mainnode.plexnode.org:8545', - fallback: 'https://canto.slingshot.finance', + primary: getOmniRpcUrl(7700), + fallback: 'https://mainnode.plexnode.org:8545', }, explorerUrl: 'https://tuber.build/', explorerName: 'Canto Explorer', @@ -111,8 +112,8 @@ export const OPTIMISM: Chain = { id: 10, name: 'Optimism', rpcUrls: { - primary: 'https://mainnet.optimism.io', - fallback: 'https://1rpc.io/op', + primary: getOmniRpcUrl(10), + fallback: 'https://mainnet.optimism.io', }, explorerUrl: 'https://optimistic.etherscan.io', explorerName: 'Optimism Explorer', @@ -132,8 +133,8 @@ export const POLYGON: Chain = { id: 137, name: 'Polygon', rpcUrls: { - primary: 'https://polygon-bor.publicnode.com', - fallback: 'https://polygon.llamarpc.com', + primary: getOmniRpcUrl(137), + fallback: 'https://polygon-bor.publicnode.com', }, explorerUrl: 'https://polygonscan.com', explorerName: 'PolygonScan', @@ -153,8 +154,8 @@ export const DFK: Chain = { id: 53935, name: 'DFK Chain', rpcUrls: { - primary: 'https://subnets.avax.network/defi-kingdoms/dfk-chain/rpc', - fallback: 'https://dfkchain.api.onfinality.io/public', + primary: getOmniRpcUrl(53935), + fallback: 'https://subnets.avax.network/defi-kingdoms/dfk-chain/rpc', }, explorerUrl: 'https://subnets.avax.network/defi-kingdoms', explorerName: 'DFK Subnet Explorer', @@ -174,8 +175,8 @@ export const KLAYTN: Chain = { id: 8217, name: 'Klaytn', rpcUrls: { - primary: 'https://klaytn.blockpi.network/v1/rpc/public', - fallback: 'https://klaytn.api.onfinality.io/public', + primary: getOmniRpcUrl(8217), + fallback: 'https://klaytn.blockpi.network/v1/rpc/public', }, explorerUrl: 'https://scope.klaytn.com', explorerName: 'Klaytn Explorer', @@ -195,8 +196,8 @@ export const FANTOM: Chain = { id: 250, name: 'Fantom', rpcUrls: { - primary: 'https://rpc.ftm.tools', - fallback: 'https://fantom-rpc.gateway.pokt.network/', + primary: getOmniRpcUrl(250), + fallback: 'https://rpc.ftm.tools', }, explorerUrl: 'https://ftmscan.com', explorerName: 'FTMScan', @@ -216,8 +217,8 @@ export const CRONOS: Chain = { id: 25, name: 'Cronos', rpcUrls: { - primary: 'https://evm-cronos.crypto.org', - fallback: 'https://cronos.blockpi.network/v1/rpc/public', + primary: getOmniRpcUrl(25), + fallback: 'https://evm-cronos.crypto.org', }, explorerUrl: 'https://cronoscan.com', explorerName: 'CronoScan', @@ -237,8 +238,8 @@ export const BOBA: Chain = { id: 288, name: 'Boba Chain', rpcUrls: { - primary: 'https://mainnet.boba.network', - fallback: 'https://replica.boba.network', + primary: getOmniRpcUrl(288), + fallback: 'https://mainnet.boba.network', }, explorerUrl: 'https://bobascan.com', explorerName: 'Boba Explorer', @@ -258,8 +259,8 @@ export const METIS: Chain = { id: 1088, name: 'Metis', rpcUrls: { - primary: 'https://andromeda.metis.io/?owner=1088', - fallback: 'https://metis-mainnet.public.blastapi.io', + primary: getOmniRpcUrl(1088), + fallback: 'https://andromeda.metis.io/?owner=1088', }, explorerUrl: 'https://andromeda-explorer.metis.io', explorerName: 'Metis Explorer', @@ -279,8 +280,8 @@ export const AURORA: Chain = { id: 1313161554, name: 'Aurora', rpcUrls: { - primary: 'https://mainnet.aurora.dev', - fallback: 'https://1rpc.io/aurora', + primary: getOmniRpcUrl(1313161554), + fallback: 'https://mainnet.aurora.dev', }, explorerUrl: 'https://explorer.mainnet.aurora.dev', explorerName: 'Aurora Explorer', @@ -300,8 +301,8 @@ export const HARMONY: Chain = { id: 1666600000, name: 'Harmony', rpcUrls: { - primary: 'https://api.harmony.one', - fallback: 'https://api.s0.t.hmny.io', + primary: getOmniRpcUrl(1666600000), + fallback: 'https://api.harmony.one', }, explorerUrl: 'https://explorer.harmony.one', explorerName: 'Harmony Explorer', @@ -321,8 +322,8 @@ export const MOONBEAM: Chain = { id: 1284, name: 'Moonbeam', rpcUrls: { - primary: 'https://rpc.api.moonbeam.network', - fallback: 'https://moonbeam.public.blastapi.io', + primary: getOmniRpcUrl(1284), + fallback: 'https://rpc.api.moonbeam.network', }, explorerUrl: 'https://moonbeam.moonscan.io', explorerName: 'Moonbeam Explorer', @@ -342,8 +343,8 @@ export const MOONRIVER: Chain = { id: 1285, name: 'Moonriver', rpcUrls: { - primary: 'https://rpc.api.moonriver.moonbeam.network', - fallback: 'https://moonriver.public.blastapi.io', + primary: getOmniRpcUrl(1285), + fallback: 'https://rpc.api.moonriver.moonbeam.network', }, explorerUrl: 'https://moonriver.moonscan.io', explorerName: 'Moonriver Explorer', @@ -363,8 +364,8 @@ export const DOGE: Chain = { id: 2000, name: 'Dogechain', rpcUrls: { - primary: 'https://rpc.dogechain.dog', - fallback: 'https://rpc01-sg.dogechain.dog', + primary: getOmniRpcUrl(2000), + fallback: 'https://rpc.dogechain.dog', }, explorerUrl: 'https://explorer.dogechain.dog', explorerName: 'Dogechain Explorer', @@ -384,8 +385,8 @@ export const BASE: Chain = { id: 8453, name: 'Base', rpcUrls: { - primary: 'https://base.blockpi.network/v1/rpc/public', - fallback: 'https://developer-access-mainnet.base.org', + primary: getOmniRpcUrl(8453), + fallback: 'https://base.blockpi.network/v1/rpc/public', }, explorerUrl: 'https://basescan.org', explorerName: 'BaseScan', @@ -405,9 +406,9 @@ export const BLAST: Chain = { id: 81457, name: 'Blast', rpcUrls: { - primary: + primary: getOmniRpcUrl(81457), + fallback: 'https://lingering-indulgent-replica.blast-mainnet.quiknode.pro/6667a8f4be701cb6549b415d567bc706fb2f13a8/', - fallback: 'https://blast.blockpi.network/v1/rpc/publicChain', }, explorerUrl: 'https://blastscan.io', explorerName: 'Blastscan', @@ -427,8 +428,8 @@ export const SCROLL: Chain = { id: 534352, name: 'Scroll', rpcUrls: { - primary: 'https://rpc.scroll.io/', - fallback: 'https://scroll.blockpi.network/v1/rpc/public', + primary: getOmniRpcUrl(534352), + fallback: 'https://rpc.scroll.io/', }, explorerUrl: 'https://scrollscan.com', explorerName: 'Scrollscan', @@ -448,8 +449,8 @@ export const LINEA: Chain = { id: 59144, name: 'Linea', rpcUrls: { - primary: 'https://rpc.linea.build', - fallback: 'https://linea.blockpi.network/v1/rpc/public', + primary: getOmniRpcUrl(59144), + fallback: 'https://rpc.linea.build', }, explorerUrl: 'https://lineascan.build', explorerName: 'LineaScan', diff --git a/packages/rest-api/src/services/synapseService.ts b/packages/rest-api/src/services/synapseService.ts index a76b9b729c..c9306a0c82 100644 --- a/packages/rest-api/src/services/synapseService.ts +++ b/packages/rest-api/src/services/synapseService.ts @@ -4,7 +4,8 @@ import { SynapseSDK } from '@synapsecns/sdk-router' import { CHAINS_ARRAY } from '../constants/chains' const providers = CHAINS_ARRAY.map( - (chain) => new JsonRpcProvider(chain.rpcUrls.primary) + (chain) => + new JsonRpcProvider(chain.rpcUrls.primary || chain.rpcUrls.fallback) ) const chainIds = CHAINS_ARRAY.map((chain) => chain.id) diff --git a/packages/rest-api/src/utils/getOmniRpcUrl.ts b/packages/rest-api/src/utils/getOmniRpcUrl.ts new file mode 100644 index 0000000000..c635d86c1a --- /dev/null +++ b/packages/rest-api/src/utils/getOmniRpcUrl.ts @@ -0,0 +1,10 @@ +import * as dotenv from 'dotenv' + +dotenv.config() + +export const getOmniRpcUrl = (chainId: number) => { + if (!process.env.OMNIRPC_BASE_URL) { + return null + } + return `${process.env.OMNIRPC_BASE_URL}/${chainId}` +} diff --git a/yarn.lock b/yarn.lock index bbf0529519..a02e4af4de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1556,7 +1556,7 @@ "@babel/parser" "^7.25.7" "@babel/types" "^7.25.7" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.1.6", "@babel/traverse@^7.11.5", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.22.8", "@babel/traverse@^7.23.2", "@babel/traverse@^7.25.7", "@babel/traverse@^7.7.0": +"@babel/traverse@^7.1.0", "@babel/traverse@^7.1.6", "@babel/traverse@^7.11.5", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.22.8", "@babel/traverse@^7.23.2", "@babel/traverse@^7.25.7", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.7.tgz#83e367619be1cab8e4f2892ef30ba04c26a40fa8" integrity sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg== @@ -4229,6 +4229,18 @@ jest-util "^25.5.0" slash "^3.0.0" +"@jest/console@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-28.1.3.tgz#2030606ec03a18c31803b8a36382762e447655df" + integrity sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + slash "^3.0.0" + "@jest/console@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" @@ -4275,6 +4287,41 @@ slash "^3.0.0" strip-ansi "^6.0.0" +"@jest/core@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.3.tgz#0ebf2bd39840f1233cd5f2d1e6fc8b71bd5a1ac7" + integrity sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA== + dependencies: + "@jest/console" "^28.1.3" + "@jest/reporters" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^28.1.3" + jest-config "^28.1.3" + jest-haste-map "^28.1.3" + jest-message-util "^28.1.3" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-resolve-dependencies "^28.1.3" + jest-runner "^28.1.3" + jest-runtime "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + jest-watcher "^28.1.3" + micromatch "^4.0.4" + pretty-format "^28.1.3" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + "@jest/core@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" @@ -4318,6 +4365,16 @@ "@jest/types" "^25.5.0" jest-mock "^25.5.0" +"@jest/environment@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-28.1.3.tgz#abed43a6b040a4c24fdcb69eab1f97589b2d663e" + integrity sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA== + dependencies: + "@jest/fake-timers" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + jest-mock "^28.1.3" + "@jest/environment@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" @@ -4328,6 +4385,13 @@ "@types/node" "*" jest-mock "^29.7.0" +"@jest/expect-utils@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-28.1.3.tgz#58561ce5db7cd253a7edddbc051fb39dda50f525" + integrity sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA== + dependencies: + jest-get-type "^28.0.2" + "@jest/expect-utils@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" @@ -4335,6 +4399,14 @@ dependencies: jest-get-type "^29.6.3" +"@jest/expect@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-28.1.3.tgz#9ac57e1d4491baca550f6bdbd232487177ad6a72" + integrity sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw== + dependencies: + expect "^28.1.3" + jest-snapshot "^28.1.3" + "@jest/expect@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" @@ -4354,6 +4426,18 @@ jest-util "^25.5.0" lolex "^5.0.0" +"@jest/fake-timers@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-28.1.3.tgz#230255b3ad0a3d4978f1d06f70685baea91c640e" + integrity sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw== + dependencies: + "@jest/types" "^28.1.3" + "@sinonjs/fake-timers" "^9.1.2" + "@types/node" "*" + jest-message-util "^28.1.3" + jest-mock "^28.1.3" + jest-util "^28.1.3" + "@jest/fake-timers@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" @@ -4375,6 +4459,15 @@ "@jest/types" "^25.5.0" expect "^25.5.0" +"@jest/globals@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-28.1.3.tgz#a601d78ddc5fdef542728309894895b4a42dc333" + integrity sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/expect" "^28.1.3" + "@jest/types" "^28.1.3" + "@jest/globals@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" @@ -4417,6 +4510,37 @@ optionalDependencies: node-notifier "^6.0.0" +"@jest/reporters@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-28.1.3.tgz#9adf6d265edafc5fc4a434cfb31e2df5a67a369a" + integrity sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@jridgewell/trace-mapping" "^0.3.13" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + jest-worker "^28.1.3" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + terminal-link "^2.0.0" + v8-to-istanbul "^9.0.1" + "@jest/reporters@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" @@ -4447,6 +4571,13 @@ strip-ansi "^6.0.0" v8-to-istanbul "^9.0.1" +"@jest/schemas@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-28.1.3.tgz#ad8b86a66f11f33619e3d7e1dcddd7f2d40ff905" + integrity sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg== + dependencies: + "@sinclair/typebox" "^0.24.1" + "@jest/schemas@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" @@ -4463,6 +4594,15 @@ graceful-fs "^4.2.4" source-map "^0.6.0" +"@jest/source-map@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.1.2.tgz#7fe832b172b497d6663cdff6c13b0a920e139e24" + integrity sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww== + dependencies: + "@jridgewell/trace-mapping" "^0.3.13" + callsites "^3.0.0" + graceful-fs "^4.2.9" + "@jest/source-map@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" @@ -4482,6 +4622,16 @@ "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" +"@jest/test-result@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-28.1.3.tgz#5eae945fd9f4b8fcfce74d239e6f725b6bf076c5" + integrity sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg== + dependencies: + "@jest/console" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + "@jest/test-result@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" @@ -4503,6 +4653,16 @@ jest-runner "^25.5.4" jest-runtime "^25.5.4" +"@jest/test-sequencer@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz#9d0c283d906ac599c74bde464bc0d7e6a82886c3" + integrity sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw== + dependencies: + "@jest/test-result" "^28.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + slash "^3.0.0" + "@jest/test-sequencer@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" @@ -4556,6 +4716,27 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" +"@jest/transform@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-28.1.3.tgz#59d8098e50ab07950e0f2fc0fc7ec462371281b0" + integrity sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^28.1.3" + "@jridgewell/trace-mapping" "^0.3.13" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-regex-util "^28.0.2" + jest-util "^28.1.3" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.1" + "@jest/transform@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" @@ -4618,6 +4799,18 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" +"@jest/types@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.3.tgz#b05de80996ff12512bc5ceb1d208285a7d11748b" + integrity sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ== + dependencies: + "@jest/schemas" "^28.1.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@jest/types@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" @@ -4670,7 +4863,7 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -7347,6 +7540,11 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== +"@sinclair/typebox@^0.24.1": + version "0.24.51" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f" + integrity sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA== + "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -7388,6 +7586,13 @@ dependencies: "@sinonjs/commons" "^3.0.0" +"@sinonjs/fake-timers@^9.1.2": + version "9.1.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" + integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== + dependencies: + "@sinonjs/commons" "^1.7.0" + "@slorber/remark-comment@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@slorber/remark-comment/-/remark-comment-1.0.0.tgz#2a020b3f4579c89dec0361673206c28d67e08f5a" @@ -8612,14 +8817,6 @@ "@swc/counter" "^0.1.3" tslib "^2.4.0" -"@synapsecns/coverage-aggregator@file:./packages/coverage-aggregator": - version "1.0.6" - dependencies: - glob "^8.0.3" - path "^0.12.7" - ts-jest "^29.0.5" - yargs "^17.6.2" - "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" @@ -9533,7 +9730,7 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.19.1.tgz#33509849f8e679e4add158959fdb086440e9553f" integrity sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ== -"@types/prettier@^2.1.1": +"@types/prettier@^2.1.1", "@types/prettier@^2.1.5": version "2.7.3" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== @@ -12091,6 +12288,19 @@ babel-jest@^25.2.6, babel-jest@^25.5.1: graceful-fs "^4.2.4" slash "^3.0.0" +babel-jest@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.3.tgz#c1187258197c099072156a0a121c11ee1e3917d5" + integrity sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q== + dependencies: + "@jest/transform" "^28.1.3" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^28.1.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" @@ -12195,6 +12405,16 @@ babel-plugin-jest-hoist@^25.5.0: "@babel/types" "^7.3.3" "@types/babel__traverse" "^7.0.6" +babel-plugin-jest-hoist@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz#1952c4d0ea50f2d6d794353762278d1d8cca3fbe" + integrity sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + babel-plugin-jest-hoist@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" @@ -12390,6 +12610,14 @@ babel-preset-jest@^25.5.0: babel-plugin-jest-hoist "^25.5.0" babel-preset-current-node-syntax "^0.1.2" +babel-preset-jest@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz#5dfc20b99abed5db994406c2b9ab94c73aaa419d" + integrity sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A== + dependencies: + babel-plugin-jest-hoist "^28.1.3" + babel-preset-current-node-syntax "^1.0.0" + babel-preset-jest@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" @@ -15693,6 +15921,11 @@ diff-sequences@^25.2.6: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== +diff-sequences@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" + integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw== + diff-sequences@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" @@ -16122,6 +16355,11 @@ elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5.4, elliptic@^6. minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emittery@^0.10.2: + version "0.10.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" + integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== + emittery@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" @@ -17922,6 +18160,17 @@ expect@^25.5.0: jest-message-util "^25.5.0" jest-regex-util "^25.2.6" +expect@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/expect/-/expect-28.1.3.tgz#90a7c1a124f1824133dd4533cce2d2bdcb6603ec" + integrity sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g== + dependencies: + "@jest/expect-utils" "^28.1.3" + jest-get-type "^28.0.2" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + expect@^29.0.0, expect@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" @@ -21636,7 +21885,7 @@ istanbul-lib-instrument@^4.0.0: istanbul-lib-coverage "^3.0.0" semver "^6.3.0" -istanbul-lib-instrument@^5.0.4: +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: version "5.2.1" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== @@ -21748,6 +21997,14 @@ jest-changed-files@^25.5.0: execa "^3.2.0" throat "^5.0.0" +jest-changed-files@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-28.1.3.tgz#d9aeee6792be3686c47cb988a8eaf82ff4238831" + integrity sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + jest-changed-files@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" @@ -21757,6 +22014,31 @@ jest-changed-files@^29.7.0: jest-util "^29.7.0" p-limit "^3.1.0" +jest-circus@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-28.1.3.tgz#d14bd11cf8ee1a03d69902dc47b6bd4634ee00e4" + integrity sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/expect" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + is-generator-fn "^2.0.0" + jest-each "^28.1.3" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-runtime "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + p-limit "^3.1.0" + pretty-format "^28.1.3" + slash "^3.0.0" + stack-utils "^2.0.3" + jest-circus@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" @@ -21803,6 +22085,24 @@ jest-cli@^25.5.4: realpath-native "^2.0.0" yargs "^15.3.1" +jest-cli@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.3.tgz#558b33c577d06de55087b8448d373b9f654e46b2" + integrity sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ== + dependencies: + "@jest/core" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + prompts "^2.0.1" + yargs "^17.3.1" + jest-cli@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" @@ -21845,6 +22145,34 @@ jest-config@^25.5.4: pretty-format "^25.5.0" realpath-native "^2.0.0" +jest-config@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.3.tgz#e315e1f73df3cac31447eed8b8740a477392ec60" + integrity sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^28.1.3" + "@jest/types" "^28.1.3" + babel-jest "^28.1.3" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^28.1.3" + jest-environment-node "^28.1.3" + jest-get-type "^28.0.2" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-runner "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^28.1.3" + slash "^3.0.0" + strip-json-comments "^3.1.1" + jest-config@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" @@ -21893,6 +22221,16 @@ jest-diff@^25.2.1, jest-diff@^25.5.0: jest-get-type "^25.2.6" pretty-format "^25.5.0" +jest-diff@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.3.tgz#948a192d86f4e7a64c5264ad4da4877133d8792f" + integrity sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw== + dependencies: + chalk "^4.0.0" + diff-sequences "^28.1.1" + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + jest-diff@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" @@ -21910,6 +22248,13 @@ jest-docblock@^25.3.0: dependencies: detect-newline "^3.0.0" +jest-docblock@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-28.1.1.tgz#6f515c3bf841516d82ecd57a62eed9204c2f42a8" + integrity sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA== + dependencies: + detect-newline "^3.0.0" + jest-docblock@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" @@ -21928,6 +22273,17 @@ jest-each@^25.5.0: jest-util "^25.5.0" pretty-format "^25.5.0" +jest-each@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-28.1.3.tgz#bdd1516edbe2b1f3569cfdad9acd543040028f81" + integrity sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g== + dependencies: + "@jest/types" "^28.1.3" + chalk "^4.0.0" + jest-get-type "^28.0.2" + jest-util "^28.1.3" + pretty-format "^28.1.3" + jest-each@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" @@ -21963,6 +22319,18 @@ jest-environment-node@^25.5.0: jest-util "^25.5.0" semver "^6.3.0" +jest-environment-node@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-28.1.3.tgz#7e74fe40eb645b9d56c0c4b70ca4357faa349be5" + integrity sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/fake-timers" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + jest-mock "^28.1.3" + jest-util "^28.1.3" + jest-environment-node@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" @@ -21993,6 +22361,11 @@ jest-get-type@^25.2.6: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== +jest-get-type@^28.0.2: + version "28.0.2" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" + integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== + jest-get-type@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" @@ -22039,6 +22412,25 @@ jest-haste-map@^26.6.2: optionalDependencies: fsevents "^2.1.2" +jest-haste-map@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-28.1.3.tgz#abd5451129a38d9841049644f34b034308944e2b" + integrity sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA== + dependencies: + "@jest/types" "^28.1.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^28.0.2" + jest-util "^28.1.3" + jest-worker "^28.1.3" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + jest-haste-map@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" @@ -22089,6 +22481,14 @@ jest-leak-detector@^25.5.0: jest-get-type "^25.2.6" pretty-format "^25.5.0" +jest-leak-detector@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz#a6685d9b074be99e3adee816ce84fd30795e654d" + integrity sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA== + dependencies: + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + jest-leak-detector@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" @@ -22107,6 +22507,16 @@ jest-matcher-utils@^25.5.0: jest-get-type "^25.2.6" pretty-format "^25.5.0" +jest-matcher-utils@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz#5a77f1c129dd5ba3b4d7fc20728806c78893146e" + integrity sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw== + dependencies: + chalk "^4.0.0" + jest-diff "^28.1.3" + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + jest-matcher-utils@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" @@ -22131,6 +22541,21 @@ jest-message-util@^25.5.0: slash "^3.0.0" stack-utils "^1.0.1" +jest-message-util@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.3.tgz#232def7f2e333f1eecc90649b5b94b0055e7c43d" + integrity sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^28.1.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^28.1.3" + slash "^3.0.0" + stack-utils "^2.0.3" + jest-message-util@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" @@ -22168,6 +22593,14 @@ jest-mock@^27.0.6: "@jest/types" "^27.5.1" "@types/node" "*" +jest-mock@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-28.1.3.tgz#d4e9b1fc838bea595c77ab73672ebf513ab249da" + integrity sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + jest-mock@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" @@ -22192,6 +22625,11 @@ jest-regex-util@^26.0.0: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== +jest-regex-util@^28.0.2: + version "28.0.2" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead" + integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== + jest-regex-util@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" @@ -22206,6 +22644,14 @@ jest-resolve-dependencies@^25.5.4: jest-regex-util "^25.2.6" jest-snapshot "^25.5.1" +jest-resolve-dependencies@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz#8c65d7583460df7275c6ea2791901fa975c1fe66" + integrity sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA== + dependencies: + jest-regex-util "^28.0.2" + jest-snapshot "^28.1.3" + jest-resolve-dependencies@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" @@ -22229,6 +22675,21 @@ jest-resolve@^25.5.1: resolve "^1.17.0" slash "^3.0.0" +jest-resolve@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-28.1.3.tgz#cfb36100341ddbb061ec781426b3c31eb51aa0a8" + integrity sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-pnp-resolver "^1.2.2" + jest-util "^28.1.3" + jest-validate "^28.1.3" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + jest-resolve@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" @@ -22269,6 +22730,33 @@ jest-runner@^25.5.4: source-map-support "^0.5.6" throat "^5.0.0" +jest-runner@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-28.1.3.tgz#5eee25febd730b4713a2cdfd76bdd5557840f9a1" + integrity sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA== + dependencies: + "@jest/console" "^28.1.3" + "@jest/environment" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.10.2" + graceful-fs "^4.2.9" + jest-docblock "^28.1.1" + jest-environment-node "^28.1.3" + jest-haste-map "^28.1.3" + jest-leak-detector "^28.1.3" + jest-message-util "^28.1.3" + jest-resolve "^28.1.3" + jest-runtime "^28.1.3" + jest-util "^28.1.3" + jest-watcher "^28.1.3" + jest-worker "^28.1.3" + p-limit "^3.1.0" + source-map-support "0.5.13" + jest-runner@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" @@ -22328,6 +22816,34 @@ jest-runtime@^25.5.4: strip-bom "^4.0.0" yargs "^15.3.1" +jest-runtime@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-28.1.3.tgz#a57643458235aa53e8ec7821949e728960d0605f" + integrity sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/fake-timers" "^28.1.3" + "@jest/globals" "^28.1.3" + "@jest/source-map" "^28.1.2" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-message-util "^28.1.3" + jest-mock "^28.1.3" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + slash "^3.0.0" + strip-bom "^4.0.0" + jest-runtime@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" @@ -22392,6 +22908,35 @@ jest-snapshot@^25.5.1: pretty-format "^25.5.0" semver "^6.3.0" +jest-snapshot@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-28.1.3.tgz#17467b3ab8ddb81e2f605db05583d69388fc0668" + integrity sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/babel__traverse" "^7.0.6" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^28.1.3" + graceful-fs "^4.2.9" + jest-diff "^28.1.3" + jest-get-type "^28.0.2" + jest-haste-map "^28.1.3" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + natural-compare "^1.4.0" + pretty-format "^28.1.3" + semver "^7.3.5" + jest-snapshot@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" @@ -22441,6 +22986,18 @@ jest-util@^26.6.2: is-ci "^2.0.0" micromatch "^4.0.2" +jest-util@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.3.tgz#f4f932aa0074f0679943220ff9cbba7e497028b0" + integrity sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + jest-util@^29.0.0, jest-util@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" @@ -22465,6 +23022,18 @@ jest-validate@^25.5.0: leven "^3.1.0" pretty-format "^25.5.0" +jest-validate@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-28.1.3.tgz#e322267fd5e7c64cea4629612c357bbda96229df" + integrity sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA== + dependencies: + "@jest/types" "^28.1.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^28.0.2" + leven "^3.1.0" + pretty-format "^28.1.3" + jest-validate@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" @@ -22502,6 +23071,20 @@ jest-watcher@^25.2.4, jest-watcher@^25.5.0: jest-util "^25.5.0" string-length "^3.1.0" +jest-watcher@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-28.1.3.tgz#c6023a59ba2255e3b4c57179fc94164b3e73abd4" + integrity sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g== + dependencies: + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.10.2" + jest-util "^28.1.3" + string-length "^4.0.1" + jest-watcher@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" @@ -22550,6 +23133,15 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" +jest-worker@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.3.tgz#7e3c4ce3fa23d1bb6accb169e7f396f98ed4bb98" + integrity sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + jest-worker@^29.4.3, jest-worker@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" @@ -22569,6 +23161,16 @@ jest@^25.3.0: import-local "^3.0.2" jest-cli "^25.5.4" +jest@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.3.tgz#e9c6a7eecdebe3548ca2b18894a50f45b36dfc6b" + integrity sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA== + dependencies: + "@jest/core" "^28.1.3" + "@jest/types" "^28.1.3" + import-local "^3.0.2" + jest-cli "^28.1.3" + jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" @@ -28602,6 +29204,16 @@ pretty-format@^27.0.2: ansi-styles "^5.0.0" react-is "^17.0.1" +pretty-format@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.3.tgz#c9fba8cedf99ce50963a11b27d982a9ae90970d5" + integrity sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q== + dependencies: + "@jest/schemas" "^28.1.3" + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^18.0.0" + pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" @@ -30376,6 +30988,11 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== +resolve.exports@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999" + integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== + resolve.exports@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" @@ -36535,7 +37152,7 @@ write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -write-file-atomic@^4.0.2: +write-file-atomic@^4.0.1, write-file-atomic@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== From 47ceb855c1fb44136bcba4a496a68247386a3895 Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Tue, 15 Oct 2024 17:52:38 +0000 Subject: [PATCH 43/47] Publish - @synapsecns/rest-api@1.5.0 --- packages/rest-api/CHANGELOG.md | 11 +++++++++++ packages/rest-api/package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/rest-api/CHANGELOG.md b/packages/rest-api/CHANGELOG.md index 6c309e2a1b..4ecd8ebcae 100644 --- a/packages/rest-api/CHANGELOG.md +++ b/packages/rest-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.5.0](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.4.9...@synapsecns/rest-api@1.5.0) (2024-10-15) + + +### Features + +* **rest-api:** Primary RPCs get omnirpc ([#3294](https://github.com/synapsecns/sanguine/issues/3294)) ([31a3ce9](https://github.com/synapsecns/sanguine/commit/31a3ce9f1a90d47425dae6ef969b28de3895a6aa)) + + + + + ## [1.4.9](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.4.8...@synapsecns/rest-api@1.4.9) (2024-10-11) **Note:** Version bump only for package @synapsecns/rest-api diff --git a/packages/rest-api/package.json b/packages/rest-api/package.json index cc3dc43fa6..8b4a6a13ec 100644 --- a/packages/rest-api/package.json +++ b/packages/rest-api/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/rest-api", - "version": "1.4.9", + "version": "1.5.0", "private": "true", "engines": { "node": ">=18.17.0" From fd75dbbbb6fec8ad2c35d5a16efb3a6a4812231a Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:26:34 -0700 Subject: [PATCH 44/47] fix(synapse-interface): translation period (#3297) * fix period --- .../components/Activity/Activity.tsx | 2 +- .../layouts/StandardPageContainer.tsx | 2 +- yarn.lock | 643 +----------------- 3 files changed, 15 insertions(+), 632 deletions(-) diff --git a/packages/synapse-interface/components/Activity/Activity.tsx b/packages/synapse-interface/components/Activity/Activity.tsx index 5fe5012493..96a262e1d9 100644 --- a/packages/synapse-interface/components/Activity/Activity.tsx +++ b/packages/synapse-interface/components/Activity/Activity.tsx @@ -71,7 +71,7 @@ export const Activity = ({ visibility }: { visibility: boolean }) => { {viewingAddress && !isLoading && !hasHistoricalTransactions && (
- {t('No transactions in last 30 days.')} + {t('No transactions in last 30 days')}
)} diff --git a/packages/synapse-interface/components/layouts/StandardPageContainer.tsx b/packages/synapse-interface/components/layouts/StandardPageContainer.tsx index 8c408194f5..e1c5f16868 100644 --- a/packages/synapse-interface/components/layouts/StandardPageContainer.tsx +++ b/packages/synapse-interface/components/layouts/StandardPageContainer.tsx @@ -31,7 +31,7 @@ const StandardPageContainer = ({ if (unsupported) { unsupportedToaster = toast.error( - t('Connected to an unsupported network; Please switch networks.'), + t('Connected to an unsupported network; Please switch networks'), { id: 'unsupported-popup', duration: 5000 } ) } else { diff --git a/yarn.lock b/yarn.lock index a02e4af4de..bbf0529519 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1556,7 +1556,7 @@ "@babel/parser" "^7.25.7" "@babel/types" "^7.25.7" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.1.6", "@babel/traverse@^7.11.5", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.22.8", "@babel/traverse@^7.23.2", "@babel/traverse@^7.25.7", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2": +"@babel/traverse@^7.1.0", "@babel/traverse@^7.1.6", "@babel/traverse@^7.11.5", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.22.8", "@babel/traverse@^7.23.2", "@babel/traverse@^7.25.7", "@babel/traverse@^7.7.0": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.7.tgz#83e367619be1cab8e4f2892ef30ba04c26a40fa8" integrity sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg== @@ -4229,18 +4229,6 @@ jest-util "^25.5.0" slash "^3.0.0" -"@jest/console@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-28.1.3.tgz#2030606ec03a18c31803b8a36382762e447655df" - integrity sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw== - dependencies: - "@jest/types" "^28.1.3" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^28.1.3" - jest-util "^28.1.3" - slash "^3.0.0" - "@jest/console@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" @@ -4287,41 +4275,6 @@ slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/core@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.3.tgz#0ebf2bd39840f1233cd5f2d1e6fc8b71bd5a1ac7" - integrity sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA== - dependencies: - "@jest/console" "^28.1.3" - "@jest/reporters" "^28.1.3" - "@jest/test-result" "^28.1.3" - "@jest/transform" "^28.1.3" - "@jest/types" "^28.1.3" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - ci-info "^3.2.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-changed-files "^28.1.3" - jest-config "^28.1.3" - jest-haste-map "^28.1.3" - jest-message-util "^28.1.3" - jest-regex-util "^28.0.2" - jest-resolve "^28.1.3" - jest-resolve-dependencies "^28.1.3" - jest-runner "^28.1.3" - jest-runtime "^28.1.3" - jest-snapshot "^28.1.3" - jest-util "^28.1.3" - jest-validate "^28.1.3" - jest-watcher "^28.1.3" - micromatch "^4.0.4" - pretty-format "^28.1.3" - rimraf "^3.0.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - "@jest/core@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" @@ -4365,16 +4318,6 @@ "@jest/types" "^25.5.0" jest-mock "^25.5.0" -"@jest/environment@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-28.1.3.tgz#abed43a6b040a4c24fdcb69eab1f97589b2d663e" - integrity sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA== - dependencies: - "@jest/fake-timers" "^28.1.3" - "@jest/types" "^28.1.3" - "@types/node" "*" - jest-mock "^28.1.3" - "@jest/environment@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" @@ -4385,13 +4328,6 @@ "@types/node" "*" jest-mock "^29.7.0" -"@jest/expect-utils@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-28.1.3.tgz#58561ce5db7cd253a7edddbc051fb39dda50f525" - integrity sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA== - dependencies: - jest-get-type "^28.0.2" - "@jest/expect-utils@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" @@ -4399,14 +4335,6 @@ dependencies: jest-get-type "^29.6.3" -"@jest/expect@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-28.1.3.tgz#9ac57e1d4491baca550f6bdbd232487177ad6a72" - integrity sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw== - dependencies: - expect "^28.1.3" - jest-snapshot "^28.1.3" - "@jest/expect@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" @@ -4426,18 +4354,6 @@ jest-util "^25.5.0" lolex "^5.0.0" -"@jest/fake-timers@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-28.1.3.tgz#230255b3ad0a3d4978f1d06f70685baea91c640e" - integrity sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw== - dependencies: - "@jest/types" "^28.1.3" - "@sinonjs/fake-timers" "^9.1.2" - "@types/node" "*" - jest-message-util "^28.1.3" - jest-mock "^28.1.3" - jest-util "^28.1.3" - "@jest/fake-timers@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" @@ -4459,15 +4375,6 @@ "@jest/types" "^25.5.0" expect "^25.5.0" -"@jest/globals@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-28.1.3.tgz#a601d78ddc5fdef542728309894895b4a42dc333" - integrity sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA== - dependencies: - "@jest/environment" "^28.1.3" - "@jest/expect" "^28.1.3" - "@jest/types" "^28.1.3" - "@jest/globals@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" @@ -4510,37 +4417,6 @@ optionalDependencies: node-notifier "^6.0.0" -"@jest/reporters@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-28.1.3.tgz#9adf6d265edafc5fc4a434cfb31e2df5a67a369a" - integrity sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^28.1.3" - "@jest/test-result" "^28.1.3" - "@jest/transform" "^28.1.3" - "@jest/types" "^28.1.3" - "@jridgewell/trace-mapping" "^0.3.13" - "@types/node" "*" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^5.1.0" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.1.3" - jest-message-util "^28.1.3" - jest-util "^28.1.3" - jest-worker "^28.1.3" - slash "^3.0.0" - string-length "^4.0.1" - strip-ansi "^6.0.0" - terminal-link "^2.0.0" - v8-to-istanbul "^9.0.1" - "@jest/reporters@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" @@ -4571,13 +4447,6 @@ strip-ansi "^6.0.0" v8-to-istanbul "^9.0.1" -"@jest/schemas@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-28.1.3.tgz#ad8b86a66f11f33619e3d7e1dcddd7f2d40ff905" - integrity sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg== - dependencies: - "@sinclair/typebox" "^0.24.1" - "@jest/schemas@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" @@ -4594,15 +4463,6 @@ graceful-fs "^4.2.4" source-map "^0.6.0" -"@jest/source-map@^28.1.2": - version "28.1.2" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.1.2.tgz#7fe832b172b497d6663cdff6c13b0a920e139e24" - integrity sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww== - dependencies: - "@jridgewell/trace-mapping" "^0.3.13" - callsites "^3.0.0" - graceful-fs "^4.2.9" - "@jest/source-map@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" @@ -4622,16 +4482,6 @@ "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-result@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-28.1.3.tgz#5eae945fd9f4b8fcfce74d239e6f725b6bf076c5" - integrity sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg== - dependencies: - "@jest/console" "^28.1.3" - "@jest/types" "^28.1.3" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - "@jest/test-result@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" @@ -4653,16 +4503,6 @@ jest-runner "^25.5.4" jest-runtime "^25.5.4" -"@jest/test-sequencer@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz#9d0c283d906ac599c74bde464bc0d7e6a82886c3" - integrity sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw== - dependencies: - "@jest/test-result" "^28.1.3" - graceful-fs "^4.2.9" - jest-haste-map "^28.1.3" - slash "^3.0.0" - "@jest/test-sequencer@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" @@ -4716,27 +4556,6 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" -"@jest/transform@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-28.1.3.tgz#59d8098e50ab07950e0f2fc0fc7ec462371281b0" - integrity sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA== - dependencies: - "@babel/core" "^7.11.6" - "@jest/types" "^28.1.3" - "@jridgewell/trace-mapping" "^0.3.13" - babel-plugin-istanbul "^6.1.1" - chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^28.1.3" - jest-regex-util "^28.0.2" - jest-util "^28.1.3" - micromatch "^4.0.4" - pirates "^4.0.4" - slash "^3.0.0" - write-file-atomic "^4.0.1" - "@jest/transform@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" @@ -4799,18 +4618,6 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" -"@jest/types@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.3.tgz#b05de80996ff12512bc5ceb1d208285a7d11748b" - integrity sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ== - dependencies: - "@jest/schemas" "^28.1.3" - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^17.0.8" - chalk "^4.0.0" - "@jest/types@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" @@ -4863,7 +4670,7 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -7540,11 +7347,6 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== -"@sinclair/typebox@^0.24.1": - version "0.24.51" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f" - integrity sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA== - "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -7586,13 +7388,6 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@sinonjs/fake-timers@^9.1.2": - version "9.1.2" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" - integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== - dependencies: - "@sinonjs/commons" "^1.7.0" - "@slorber/remark-comment@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@slorber/remark-comment/-/remark-comment-1.0.0.tgz#2a020b3f4579c89dec0361673206c28d67e08f5a" @@ -8817,6 +8612,14 @@ "@swc/counter" "^0.1.3" tslib "^2.4.0" +"@synapsecns/coverage-aggregator@file:./packages/coverage-aggregator": + version "1.0.6" + dependencies: + glob "^8.0.3" + path "^0.12.7" + ts-jest "^29.0.5" + yargs "^17.6.2" + "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" @@ -9730,7 +9533,7 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.19.1.tgz#33509849f8e679e4add158959fdb086440e9553f" integrity sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ== -"@types/prettier@^2.1.1", "@types/prettier@^2.1.5": +"@types/prettier@^2.1.1": version "2.7.3" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== @@ -12288,19 +12091,6 @@ babel-jest@^25.2.6, babel-jest@^25.5.1: graceful-fs "^4.2.4" slash "^3.0.0" -babel-jest@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.3.tgz#c1187258197c099072156a0a121c11ee1e3917d5" - integrity sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q== - dependencies: - "@jest/transform" "^28.1.3" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^28.1.3" - chalk "^4.0.0" - graceful-fs "^4.2.9" - slash "^3.0.0" - babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" @@ -12405,16 +12195,6 @@ babel-plugin-jest-hoist@^25.5.0: "@babel/types" "^7.3.3" "@types/babel__traverse" "^7.0.6" -babel-plugin-jest-hoist@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz#1952c4d0ea50f2d6d794353762278d1d8cca3fbe" - integrity sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.1.14" - "@types/babel__traverse" "^7.0.6" - babel-plugin-jest-hoist@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" @@ -12610,14 +12390,6 @@ babel-preset-jest@^25.5.0: babel-plugin-jest-hoist "^25.5.0" babel-preset-current-node-syntax "^0.1.2" -babel-preset-jest@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz#5dfc20b99abed5db994406c2b9ab94c73aaa419d" - integrity sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A== - dependencies: - babel-plugin-jest-hoist "^28.1.3" - babel-preset-current-node-syntax "^1.0.0" - babel-preset-jest@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" @@ -15921,11 +15693,6 @@ diff-sequences@^25.2.6: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== -diff-sequences@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" - integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw== - diff-sequences@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" @@ -16355,11 +16122,6 @@ elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5.4, elliptic@^6. minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" -emittery@^0.10.2: - version "0.10.2" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" - integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== - emittery@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" @@ -18160,17 +17922,6 @@ expect@^25.5.0: jest-message-util "^25.5.0" jest-regex-util "^25.2.6" -expect@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/expect/-/expect-28.1.3.tgz#90a7c1a124f1824133dd4533cce2d2bdcb6603ec" - integrity sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g== - dependencies: - "@jest/expect-utils" "^28.1.3" - jest-get-type "^28.0.2" - jest-matcher-utils "^28.1.3" - jest-message-util "^28.1.3" - jest-util "^28.1.3" - expect@^29.0.0, expect@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" @@ -21885,7 +21636,7 @@ istanbul-lib-instrument@^4.0.0: istanbul-lib-coverage "^3.0.0" semver "^6.3.0" -istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: +istanbul-lib-instrument@^5.0.4: version "5.2.1" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== @@ -21997,14 +21748,6 @@ jest-changed-files@^25.5.0: execa "^3.2.0" throat "^5.0.0" -jest-changed-files@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-28.1.3.tgz#d9aeee6792be3686c47cb988a8eaf82ff4238831" - integrity sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA== - dependencies: - execa "^5.0.0" - p-limit "^3.1.0" - jest-changed-files@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" @@ -22014,31 +21757,6 @@ jest-changed-files@^29.7.0: jest-util "^29.7.0" p-limit "^3.1.0" -jest-circus@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-28.1.3.tgz#d14bd11cf8ee1a03d69902dc47b6bd4634ee00e4" - integrity sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow== - dependencies: - "@jest/environment" "^28.1.3" - "@jest/expect" "^28.1.3" - "@jest/test-result" "^28.1.3" - "@jest/types" "^28.1.3" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - dedent "^0.7.0" - is-generator-fn "^2.0.0" - jest-each "^28.1.3" - jest-matcher-utils "^28.1.3" - jest-message-util "^28.1.3" - jest-runtime "^28.1.3" - jest-snapshot "^28.1.3" - jest-util "^28.1.3" - p-limit "^3.1.0" - pretty-format "^28.1.3" - slash "^3.0.0" - stack-utils "^2.0.3" - jest-circus@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" @@ -22085,24 +21803,6 @@ jest-cli@^25.5.4: realpath-native "^2.0.0" yargs "^15.3.1" -jest-cli@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.3.tgz#558b33c577d06de55087b8448d373b9f654e46b2" - integrity sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ== - dependencies: - "@jest/core" "^28.1.3" - "@jest/test-result" "^28.1.3" - "@jest/types" "^28.1.3" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - import-local "^3.0.2" - jest-config "^28.1.3" - jest-util "^28.1.3" - jest-validate "^28.1.3" - prompts "^2.0.1" - yargs "^17.3.1" - jest-cli@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" @@ -22145,34 +21845,6 @@ jest-config@^25.5.4: pretty-format "^25.5.0" realpath-native "^2.0.0" -jest-config@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.3.tgz#e315e1f73df3cac31447eed8b8740a477392ec60" - integrity sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ== - dependencies: - "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^28.1.3" - "@jest/types" "^28.1.3" - babel-jest "^28.1.3" - chalk "^4.0.0" - ci-info "^3.2.0" - deepmerge "^4.2.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-circus "^28.1.3" - jest-environment-node "^28.1.3" - jest-get-type "^28.0.2" - jest-regex-util "^28.0.2" - jest-resolve "^28.1.3" - jest-runner "^28.1.3" - jest-util "^28.1.3" - jest-validate "^28.1.3" - micromatch "^4.0.4" - parse-json "^5.2.0" - pretty-format "^28.1.3" - slash "^3.0.0" - strip-json-comments "^3.1.1" - jest-config@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" @@ -22221,16 +21893,6 @@ jest-diff@^25.2.1, jest-diff@^25.5.0: jest-get-type "^25.2.6" pretty-format "^25.5.0" -jest-diff@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.3.tgz#948a192d86f4e7a64c5264ad4da4877133d8792f" - integrity sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw== - dependencies: - chalk "^4.0.0" - diff-sequences "^28.1.1" - jest-get-type "^28.0.2" - pretty-format "^28.1.3" - jest-diff@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" @@ -22248,13 +21910,6 @@ jest-docblock@^25.3.0: dependencies: detect-newline "^3.0.0" -jest-docblock@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-28.1.1.tgz#6f515c3bf841516d82ecd57a62eed9204c2f42a8" - integrity sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA== - dependencies: - detect-newline "^3.0.0" - jest-docblock@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" @@ -22273,17 +21928,6 @@ jest-each@^25.5.0: jest-util "^25.5.0" pretty-format "^25.5.0" -jest-each@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-28.1.3.tgz#bdd1516edbe2b1f3569cfdad9acd543040028f81" - integrity sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g== - dependencies: - "@jest/types" "^28.1.3" - chalk "^4.0.0" - jest-get-type "^28.0.2" - jest-util "^28.1.3" - pretty-format "^28.1.3" - jest-each@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" @@ -22319,18 +21963,6 @@ jest-environment-node@^25.5.0: jest-util "^25.5.0" semver "^6.3.0" -jest-environment-node@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-28.1.3.tgz#7e74fe40eb645b9d56c0c4b70ca4357faa349be5" - integrity sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A== - dependencies: - "@jest/environment" "^28.1.3" - "@jest/fake-timers" "^28.1.3" - "@jest/types" "^28.1.3" - "@types/node" "*" - jest-mock "^28.1.3" - jest-util "^28.1.3" - jest-environment-node@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" @@ -22361,11 +21993,6 @@ jest-get-type@^25.2.6: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== -jest-get-type@^28.0.2: - version "28.0.2" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" - integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== - jest-get-type@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" @@ -22412,25 +22039,6 @@ jest-haste-map@^26.6.2: optionalDependencies: fsevents "^2.1.2" -jest-haste-map@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-28.1.3.tgz#abd5451129a38d9841049644f34b034308944e2b" - integrity sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA== - dependencies: - "@jest/types" "^28.1.3" - "@types/graceful-fs" "^4.1.3" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^28.0.2" - jest-util "^28.1.3" - jest-worker "^28.1.3" - micromatch "^4.0.4" - walker "^1.0.8" - optionalDependencies: - fsevents "^2.3.2" - jest-haste-map@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" @@ -22481,14 +22089,6 @@ jest-leak-detector@^25.5.0: jest-get-type "^25.2.6" pretty-format "^25.5.0" -jest-leak-detector@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz#a6685d9b074be99e3adee816ce84fd30795e654d" - integrity sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA== - dependencies: - jest-get-type "^28.0.2" - pretty-format "^28.1.3" - jest-leak-detector@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" @@ -22507,16 +22107,6 @@ jest-matcher-utils@^25.5.0: jest-get-type "^25.2.6" pretty-format "^25.5.0" -jest-matcher-utils@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz#5a77f1c129dd5ba3b4d7fc20728806c78893146e" - integrity sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw== - dependencies: - chalk "^4.0.0" - jest-diff "^28.1.3" - jest-get-type "^28.0.2" - pretty-format "^28.1.3" - jest-matcher-utils@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" @@ -22541,21 +22131,6 @@ jest-message-util@^25.5.0: slash "^3.0.0" stack-utils "^1.0.1" -jest-message-util@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.3.tgz#232def7f2e333f1eecc90649b5b94b0055e7c43d" - integrity sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^28.1.3" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - micromatch "^4.0.4" - pretty-format "^28.1.3" - slash "^3.0.0" - stack-utils "^2.0.3" - jest-message-util@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" @@ -22593,14 +22168,6 @@ jest-mock@^27.0.6: "@jest/types" "^27.5.1" "@types/node" "*" -jest-mock@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-28.1.3.tgz#d4e9b1fc838bea595c77ab73672ebf513ab249da" - integrity sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA== - dependencies: - "@jest/types" "^28.1.3" - "@types/node" "*" - jest-mock@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" @@ -22625,11 +22192,6 @@ jest-regex-util@^26.0.0: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== -jest-regex-util@^28.0.2: - version "28.0.2" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead" - integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== - jest-regex-util@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" @@ -22644,14 +22206,6 @@ jest-resolve-dependencies@^25.5.4: jest-regex-util "^25.2.6" jest-snapshot "^25.5.1" -jest-resolve-dependencies@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz#8c65d7583460df7275c6ea2791901fa975c1fe66" - integrity sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA== - dependencies: - jest-regex-util "^28.0.2" - jest-snapshot "^28.1.3" - jest-resolve-dependencies@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" @@ -22675,21 +22229,6 @@ jest-resolve@^25.5.1: resolve "^1.17.0" slash "^3.0.0" -jest-resolve@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-28.1.3.tgz#cfb36100341ddbb061ec781426b3c31eb51aa0a8" - integrity sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ== - dependencies: - chalk "^4.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^28.1.3" - jest-pnp-resolver "^1.2.2" - jest-util "^28.1.3" - jest-validate "^28.1.3" - resolve "^1.20.0" - resolve.exports "^1.1.0" - slash "^3.0.0" - jest-resolve@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" @@ -22730,33 +22269,6 @@ jest-runner@^25.5.4: source-map-support "^0.5.6" throat "^5.0.0" -jest-runner@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-28.1.3.tgz#5eee25febd730b4713a2cdfd76bdd5557840f9a1" - integrity sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA== - dependencies: - "@jest/console" "^28.1.3" - "@jest/environment" "^28.1.3" - "@jest/test-result" "^28.1.3" - "@jest/transform" "^28.1.3" - "@jest/types" "^28.1.3" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.10.2" - graceful-fs "^4.2.9" - jest-docblock "^28.1.1" - jest-environment-node "^28.1.3" - jest-haste-map "^28.1.3" - jest-leak-detector "^28.1.3" - jest-message-util "^28.1.3" - jest-resolve "^28.1.3" - jest-runtime "^28.1.3" - jest-util "^28.1.3" - jest-watcher "^28.1.3" - jest-worker "^28.1.3" - p-limit "^3.1.0" - source-map-support "0.5.13" - jest-runner@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" @@ -22816,34 +22328,6 @@ jest-runtime@^25.5.4: strip-bom "^4.0.0" yargs "^15.3.1" -jest-runtime@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-28.1.3.tgz#a57643458235aa53e8ec7821949e728960d0605f" - integrity sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw== - dependencies: - "@jest/environment" "^28.1.3" - "@jest/fake-timers" "^28.1.3" - "@jest/globals" "^28.1.3" - "@jest/source-map" "^28.1.2" - "@jest/test-result" "^28.1.3" - "@jest/transform" "^28.1.3" - "@jest/types" "^28.1.3" - chalk "^4.0.0" - cjs-module-lexer "^1.0.0" - collect-v8-coverage "^1.0.0" - execa "^5.0.0" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-haste-map "^28.1.3" - jest-message-util "^28.1.3" - jest-mock "^28.1.3" - jest-regex-util "^28.0.2" - jest-resolve "^28.1.3" - jest-snapshot "^28.1.3" - jest-util "^28.1.3" - slash "^3.0.0" - strip-bom "^4.0.0" - jest-runtime@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" @@ -22908,35 +22392,6 @@ jest-snapshot@^25.5.1: pretty-format "^25.5.0" semver "^6.3.0" -jest-snapshot@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-28.1.3.tgz#17467b3ab8ddb81e2f605db05583d69388fc0668" - integrity sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg== - dependencies: - "@babel/core" "^7.11.6" - "@babel/generator" "^7.7.2" - "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/traverse" "^7.7.2" - "@babel/types" "^7.3.3" - "@jest/expect-utils" "^28.1.3" - "@jest/transform" "^28.1.3" - "@jest/types" "^28.1.3" - "@types/babel__traverse" "^7.0.6" - "@types/prettier" "^2.1.5" - babel-preset-current-node-syntax "^1.0.0" - chalk "^4.0.0" - expect "^28.1.3" - graceful-fs "^4.2.9" - jest-diff "^28.1.3" - jest-get-type "^28.0.2" - jest-haste-map "^28.1.3" - jest-matcher-utils "^28.1.3" - jest-message-util "^28.1.3" - jest-util "^28.1.3" - natural-compare "^1.4.0" - pretty-format "^28.1.3" - semver "^7.3.5" - jest-snapshot@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" @@ -22986,18 +22441,6 @@ jest-util@^26.6.2: is-ci "^2.0.0" micromatch "^4.0.2" -jest-util@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.3.tgz#f4f932aa0074f0679943220ff9cbba7e497028b0" - integrity sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ== - dependencies: - "@jest/types" "^28.1.3" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - jest-util@^29.0.0, jest-util@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" @@ -23022,18 +22465,6 @@ jest-validate@^25.5.0: leven "^3.1.0" pretty-format "^25.5.0" -jest-validate@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-28.1.3.tgz#e322267fd5e7c64cea4629612c357bbda96229df" - integrity sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA== - dependencies: - "@jest/types" "^28.1.3" - camelcase "^6.2.0" - chalk "^4.0.0" - jest-get-type "^28.0.2" - leven "^3.1.0" - pretty-format "^28.1.3" - jest-validate@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" @@ -23071,20 +22502,6 @@ jest-watcher@^25.2.4, jest-watcher@^25.5.0: jest-util "^25.5.0" string-length "^3.1.0" -jest-watcher@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-28.1.3.tgz#c6023a59ba2255e3b4c57179fc94164b3e73abd4" - integrity sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g== - dependencies: - "@jest/test-result" "^28.1.3" - "@jest/types" "^28.1.3" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - emittery "^0.10.2" - jest-util "^28.1.3" - string-length "^4.0.1" - jest-watcher@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" @@ -23133,15 +22550,6 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -jest-worker@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.3.tgz#7e3c4ce3fa23d1bb6accb169e7f396f98ed4bb98" - integrity sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - jest-worker@^29.4.3, jest-worker@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" @@ -23161,16 +22569,6 @@ jest@^25.3.0: import-local "^3.0.2" jest-cli "^25.5.4" -jest@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.3.tgz#e9c6a7eecdebe3548ca2b18894a50f45b36dfc6b" - integrity sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA== - dependencies: - "@jest/core" "^28.1.3" - "@jest/types" "^28.1.3" - import-local "^3.0.2" - jest-cli "^28.1.3" - jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" @@ -29204,16 +28602,6 @@ pretty-format@^27.0.2: ansi-styles "^5.0.0" react-is "^17.0.1" -pretty-format@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.3.tgz#c9fba8cedf99ce50963a11b27d982a9ae90970d5" - integrity sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q== - dependencies: - "@jest/schemas" "^28.1.3" - ansi-regex "^5.0.1" - ansi-styles "^5.0.0" - react-is "^18.0.0" - pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" @@ -30988,11 +30376,6 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== -resolve.exports@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999" - integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== - resolve.exports@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" @@ -37152,7 +36535,7 @@ write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -write-file-atomic@^4.0.1, write-file-atomic@^4.0.2: +write-file-atomic@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== From 3cc5077d535cd45d56f3dacdbf80e0d24478e326 Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Tue, 15 Oct 2024 21:31:01 +0000 Subject: [PATCH 45/47] Publish - @synapsecns/synapse-interface@0.40.10 --- packages/synapse-interface/CHANGELOG.md | 11 +++++++++++ packages/synapse-interface/package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/synapse-interface/CHANGELOG.md b/packages/synapse-interface/CHANGELOG.md index e6a6670415..735878108a 100644 --- a/packages/synapse-interface/CHANGELOG.md +++ b/packages/synapse-interface/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.40.10](https://github.com/synapsecns/sanguine/compare/@synapsecns/synapse-interface@0.40.9...@synapsecns/synapse-interface@0.40.10) (2024-10-15) + + +### Bug Fixes + +* **synapse-interface:** translation period ([#3297](https://github.com/synapsecns/sanguine/issues/3297)) ([fd75dbb](https://github.com/synapsecns/sanguine/commit/fd75dbbbb6fec8ad2c35d5a16efb3a6a4812231a)) + + + + + ## [0.40.9](https://github.com/synapsecns/sanguine/compare/@synapsecns/synapse-interface@0.40.8...@synapsecns/synapse-interface@0.40.9) (2024-10-15) **Note:** Version bump only for package @synapsecns/synapse-interface diff --git a/packages/synapse-interface/package.json b/packages/synapse-interface/package.json index 7acf6c7973..152e129c94 100644 --- a/packages/synapse-interface/package.json +++ b/packages/synapse-interface/package.json @@ -1,6 +1,6 @@ { "name": "@synapsecns/synapse-interface", - "version": "0.40.9", + "version": "0.40.10", "private": true, "engines": { "node": ">=18.18.0" From 457aa959af98d372c50cb769036b07513a6566e4 Mon Sep 17 00:00:00 2001 From: parodime Date: Wed, 16 Oct 2024 05:18:03 -0400 Subject: [PATCH 46/47] fix dispute emit & revamp deposit xfer [SLT-295] [SLT-326] (#3293) * dispute emit relayer not guard. new Claim/Refund transfer & tests [SLT-295] * var & comment tweaks --- .../contracts-rfq/contracts/FastBridgeV2.sol | 38 ++++++++++++++----- .../contracts-rfq/test/FastBridgeV2.Src.t.sol | 17 ++++----- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/packages/contracts-rfq/contracts/FastBridgeV2.sol b/packages/contracts-rfq/contracts/FastBridgeV2.sol index b77e68a0c9..270f962cf9 100644 --- a/packages/contracts-rfq/contracts/FastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/FastBridgeV2.sol @@ -82,13 +82,15 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { revert DisputePeriodPassed(); } + address disputedRelayer = bridgeTxDetails[transactionId].proofRelayer; + // @dev relayer gets slashed effectively if dest relay has gone thru bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED; bridgeTxDetails[transactionId].proofRelayer = address(0); bridgeTxDetails[transactionId].proofBlockTimestamp = 0; bridgeTxDetails[transactionId].proofBlockNumber = 0; - emit BridgeProofDisputed(transactionId, msg.sender); + emit BridgeProofDisputed(transactionId, disputedRelayer); } /// @inheritdoc IFastBridge @@ -111,12 +113,17 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED; // transfer origin collateral back to original sender + uint256 amount = transaction.originAmount + transaction.originFeeAmount; address to = transaction.originSender; address token = transaction.originToken; - uint256 amount = transaction.originAmount + transaction.originFeeAmount; - token.universalTransfer(to, amount); - emit BridgeDepositRefunded(transactionId, to, token, amount); + if (token == UniversalTokenLib.ETH_ADDRESS) { + Address.sendValue(payable(to), amount); + } else { + IERC20(token).safeTransfer(to, amount); + } + + emit BridgeDepositRefunded(transactionId, transaction.originSender, transaction.originToken, amount); } /// @inheritdoc IFastBridge @@ -166,8 +173,10 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { // track amount of origin token owed to protocol uint256 originFeeAmount; - if (protocolFeeRate > 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS; - originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers + if (protocolFeeRate > 0) { + originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS; + originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers + } // set status to requested bytes memory request = abi.encode( @@ -298,12 +307,23 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { // update protocol fees if origin fee amount exists if (transaction.originFeeAmount > 0) protocolFees[transaction.originToken] += transaction.originFeeAmount; - // transfer origin collateral less fee to specified address address token = transaction.originToken; uint256 amount = transaction.originAmount; - token.universalTransfer(to, amount); - emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount); + // transfer origin collateral to specified address (protocol fee was pre-deducted at deposit) + if (token == UniversalTokenLib.ETH_ADDRESS) { + Address.sendValue(payable(to), amount); + } else { + IERC20(token).safeTransfer(to, amount); + } + + emit BridgeDepositClaimed( + transactionId, + bridgeTxDetails[transactionId].proofRelayer, + to, + transaction.originToken, + transaction.originAmount + ); } function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) { diff --git a/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol index 5baa42bda0..52315635dd 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol @@ -74,10 +74,9 @@ contract FastBridgeV2SrcTest is FastBridgeV2SrcBaseTest { }); } - function expectBridgeProofDisputed(bytes32 txId, address guard) public { + function expectBridgeProofDisputed(bytes32 txId, address relayer) public { vm.expectEmit(address(fastBridge)); - // Note: BridgeProofDisputed event has a mislabeled address parameter, this is actually the guard - emit BridgeProofDisputed({transactionId: txId, relayer: guard}); + emit BridgeProofDisputed({transactionId: txId, relayer: relayer}); } function expectBridgeDepositRefunded(IFastBridge.BridgeParams memory bridgeParams, bytes32 txId) public { @@ -384,11 +383,11 @@ contract FastBridgeV2SrcTest is FastBridgeV2SrcBaseTest { bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams}); expectBridgeProofProvided({txId: txId, relayer: relayerA, destTxHash: hex"01"}); prove({caller: relayerB, transactionId: txId, destTxHash: hex"01", relayer: relayerA}); - expectBridgeProofDisputed(txId, guard); + expectBridgeProofDisputed(txId, relayerA); dispute(guard, txId); expectBridgeProofProvided({txId: txId, relayer: relayerA, destTxHash: hex"02"}); prove({caller: relayerB, transactionId: txId, destTxHash: hex"02", relayer: relayerA}); - expectBridgeProofDisputed(txId, guard); + expectBridgeProofDisputed(txId, relayerA); dispute(guard, txId); expectBridgeProofProvided({txId: txId, relayer: relayerA, destTxHash: hex"03"}); prove({caller: relayerB, transactionId: txId, destTxHash: hex"03", relayer: relayerA}); @@ -660,7 +659,7 @@ contract FastBridgeV2SrcTest is FastBridgeV2SrcBaseTest { bytes32 txId = getTxId(tokenTx); bridge({caller: userA, msgValue: 0, params: tokenParams}); prove({caller: relayerA, bridgeTx: tokenTx, destTxHash: hex"01"}); - expectBridgeProofDisputed({txId: txId, guard: guard}); + expectBridgeProofDisputed({txId: txId, relayer: relayerA}); dispute({caller: guard, txId: txId}); assertEq(fastBridge.bridgeStatuses(txId), IFastBridgeV2.BridgeStatus.REQUESTED); assertEq(fastBridge.protocolFees(address(srcToken)), INITIAL_PROTOCOL_FEES_TOKEN); @@ -672,7 +671,7 @@ contract FastBridgeV2SrcTest is FastBridgeV2SrcBaseTest { bridge({caller: userA, msgValue: 0, params: tokenParams}); prove({caller: relayerA, bridgeTx: tokenTx, destTxHash: hex"01"}); skip(CLAIM_DELAY); - expectBridgeProofDisputed({txId: txId, guard: guard}); + expectBridgeProofDisputed({txId: txId, relayer: relayerA}); dispute({caller: guard, txId: txId}); assertEq(fastBridge.bridgeStatuses(txId), IFastBridgeV2.BridgeStatus.REQUESTED); assertEq(fastBridge.protocolFees(address(srcToken)), INITIAL_PROTOCOL_FEES_TOKEN); @@ -684,7 +683,7 @@ contract FastBridgeV2SrcTest is FastBridgeV2SrcBaseTest { bytes32 txId = getTxId(ethTx); bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams}); prove({caller: relayerA, bridgeTx: ethTx, destTxHash: hex"01"}); - expectBridgeProofDisputed({txId: txId, guard: guard}); + expectBridgeProofDisputed({txId: txId, relayer: relayerA}); dispute({caller: guard, txId: txId}); assertEq(fastBridge.bridgeStatuses(txId), IFastBridgeV2.BridgeStatus.REQUESTED); assertEq(fastBridge.protocolFees(ETH_ADDRESS), INITIAL_PROTOCOL_FEES_ETH); @@ -697,7 +696,7 @@ contract FastBridgeV2SrcTest is FastBridgeV2SrcBaseTest { bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams}); prove({caller: relayerA, bridgeTx: ethTx, destTxHash: hex"01"}); skip(CLAIM_DELAY); - expectBridgeProofDisputed({txId: txId, guard: guard}); + expectBridgeProofDisputed({txId: txId, relayer: relayerA}); dispute({caller: guard, txId: txId}); assertEq(fastBridge.bridgeStatuses(txId), IFastBridgeV2.BridgeStatus.REQUESTED); assertEq(fastBridge.protocolFees(ETH_ADDRESS), INITIAL_PROTOCOL_FEES_ETH); From 47dc48e8183ddec6b795fdbc62917fa8d29711d8 Mon Sep 17 00:00:00 2001 From: parodime Date: Wed, 16 Oct 2024 09:22:12 +0000 Subject: [PATCH 47/47] Publish - @synapsecns/contracts-rfq@0.8.3 --- packages/contracts-rfq/CHANGELOG.md | 8 ++++++++ packages/contracts-rfq/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/contracts-rfq/CHANGELOG.md b/packages/contracts-rfq/CHANGELOG.md index 3c3f40bb2d..10a7314cd3 100644 --- a/packages/contracts-rfq/CHANGELOG.md +++ b/packages/contracts-rfq/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.8.3](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.8.2...@synapsecns/contracts-rfq@0.8.3) (2024-10-16) + +**Note:** Version bump only for package @synapsecns/contracts-rfq + + + + + ## [0.8.2](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.8.1...@synapsecns/contracts-rfq@0.8.2) (2024-10-15) **Note:** Version bump only for package @synapsecns/contracts-rfq diff --git a/packages/contracts-rfq/package.json b/packages/contracts-rfq/package.json index 701ea12ed0..5ce11f669b 100644 --- a/packages/contracts-rfq/package.json +++ b/packages/contracts-rfq/package.json @@ -1,7 +1,7 @@ { "name": "@synapsecns/contracts-rfq", "license": "MIT", - "version": "0.8.2", + "version": "0.8.3", "description": "FastBridge contracts.", "private": true, "files": [