Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rfq-guard): v2 guard logic [SLT-387] #3324

Merged
merged 18 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 102 additions & 5 deletions services/rfq/e2e/rfq_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
})

// now we can send the money
_, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend)
_, originFastBridge := i.manager.GetFastBridgeV2(i.GetTestContext(), i.originBackend)
auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr())
tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridgev2.IFastBridgeBridgeParams{
DstChainId: uint32(i.destBackend.GetChainID()),
Expand Down Expand Up @@ -318,7 +318,7 @@
})

// now we can send the money
_, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend)
_, originFastBridge := i.manager.GetFastBridgeV2(i.GetTestContext(), i.originBackend)
auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr())
auth.TransactOpts.Value = realWantAmount
// we want 499 ETH for 500 requested within a day
Expand Down Expand Up @@ -458,7 +458,7 @@
})

// now we can send the money
_, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend)
_, originFastBridge := i.manager.GetFastBridgeV2(i.GetTestContext(), i.originBackend)
_, destRecipient := i.manager.GetRecipientMock(i.GetTestContext(), i.destBackend)
auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr())
params := fastbridgev2.IFastBridgeBridgeParams{
Expand Down Expand Up @@ -511,7 +511,7 @@
})
}

func (i *IntegrationSuite) TestDispute() {
func (i *IntegrationSuite) TestDisputeV1() {
// start the guard
go func() {
_ = i.guard.Start(i.GetTestContext())
Expand Down Expand Up @@ -551,8 +551,105 @@
_, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend)
auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr())
// we want 499 usdc for 500 requested within a day
tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridge.IFastBridgeBridgeParams{
DstChainId: uint32(i.destBackend.GetChainID()),
Sender: i.userWallet.Address(),
To: i.userWallet.Address(),
OriginToken: originUSDC.Address(),
SendChainGas: true,
DestToken: destUSDC.Address(),
OriginAmount: realRFQAmount,
DestAmount: new(big.Int).Sub(realRFQAmount, big.NewInt(10_000_000)),
Deadline: new(big.Int).SetInt64(time.Now().Add(time.Hour * 24).Unix()),
})
i.NoError(err)
i.originBackend.WaitForConfirmation(i.GetTestContext(), tx)

// fetch the txid and raw request
var txID [32]byte
var rawRequest []byte
parser, err := fastbridge.NewParser(originFastBridge.Address())
i.NoError(err)
i.Eventually(func() bool {
receipt, err := i.originBackend.TransactionReceipt(i.GetTestContext(), tx.Hash())
i.NoError(err)
for _, log := range receipt.Logs {
_, parsedEvent, ok := parser.ParseEvent(*log)
if !ok {
continue
}
event, ok := parsedEvent.(*fastbridge.FastBridgeBridgeRequested)
if ok {
txID = event.TransactionId
rawRequest = event.Request
return true
}
}
return false
})

Comment on lines +571 to +590
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential mismatch in parser usage: using fastbridge.NewParser with FastBridgeV2

In TestDisputeV2, you're creating a parser with fastbridge.NewParser(originFastBridge.Address()), but originFastBridge is a FastBridgeV2 instance. This may lead to incorrect event parsing. Consider using fastbridgev2.NewParser instead to match the contract version.

Apply this diff to use the correct parser:

-	parser, err := fastbridge.NewParser(originFastBridge.Address())
+	parser, err := fastbridgev2.NewParser(originFastBridge.Address())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
parser, err := fastbridge.NewParser(originFastBridge.Address())
i.NoError(err)
i.Eventually(func() bool {
receipt, err := i.originBackend.TransactionReceipt(i.GetTestContext(), tx.Hash())
i.NoError(err)
for _, log := range receipt.Logs {
_, parsedEvent, ok := parser.ParseEvent(*log)
if !ok {
continue
}
event, ok := parsedEvent.(*fastbridge.FastBridgeBridgeRequested)
if ok {
txID = event.TransactionId
rawRequest = event.Request
return true
}
}
return false
})
parser, err := fastbridgev2.NewParser(originFastBridge.Address())
i.NoError(err)
i.Eventually(func() bool {
receipt, err := i.originBackend.TransactionReceipt(i.GetTestContext(), tx.Hash())
i.NoError(err)
for _, log := range receipt.Logs {
_, parsedEvent, ok := parser.ParseEvent(*log)
if !ok {
continue
}
event, ok := parsedEvent.(*fastbridge.FastBridgeBridgeRequested)
if ok {
txID = event.TransactionId
rawRequest = event.Request
return true
}
}
return false
})

// call prove() from the relayer wallet before relay actually occurred on dest
relayerAuth := i.originBackend.GetTxContext(i.GetTestContext(), i.relayerWallet.AddressPtr())
fakeHash := common.HexToHash("0xdeadbeef")
tx, err = originFastBridge.Prove(relayerAuth.TransactOpts, rawRequest, fakeHash)
i.NoError(err)
i.originBackend.WaitForConfirmation(i.GetTestContext(), tx)

// verify that the guard calls Dispute()
i.Eventually(func() bool {
results, err := i.guardStore.GetPendingProvensByStatus(i.GetTestContext(), guarddb.Disputed)
i.NoError(err)
if len(results) != 1 {
return false
}
result, err := i.guardStore.GetPendingProvenByID(i.GetTestContext(), txID)
i.NoError(err)
return result.TxHash == fakeHash && result.Status == guarddb.Disputed && result.TransactionID == txID
})
}

func (i *IntegrationSuite) TestDisputeV2() {
// start the guard
go func() {
_ = i.guard.Start(i.GetTestContext())
}()

// load token contracts
const startAmount = 1000
const rfqAmount = 900
opts := i.destBackend.GetTxContext(i.GetTestContext(), nil)
destUSDC, destUSDCHandle := i.cctpDeployManager.GetMockMintBurnTokenType(i.GetTestContext(), i.destBackend)
realStartAmount, err := testutil.AdjustAmount(i.GetTestContext(), big.NewInt(startAmount), destUSDC.ContractHandle())
i.NoError(err)
realRFQAmount, err := testutil.AdjustAmount(i.GetTestContext(), big.NewInt(rfqAmount), destUSDC.ContractHandle())
i.NoError(err)

// add initial usdc to relayer on destination
tx, err := destUSDCHandle.MintPublic(opts.TransactOpts, i.relayerWallet.Address(), realStartAmount)
i.Nil(err)
i.destBackend.WaitForConfirmation(i.GetTestContext(), tx)
i.Approve(i.destBackend, destUSDC, i.relayerWallet)

// add initial USDC to relayer on origin
optsOrigin := i.originBackend.GetTxContext(i.GetTestContext(), nil)
originUSDC, originUSDCHandle := i.cctpDeployManager.GetMockMintBurnTokenType(i.GetTestContext(), i.originBackend)
tx, err = originUSDCHandle.MintPublic(optsOrigin.TransactOpts, i.relayerWallet.Address(), realStartAmount)
i.Nil(err)
i.originBackend.WaitForConfirmation(i.GetTestContext(), tx)
i.Approve(i.originBackend, originUSDC, i.relayerWallet)

// add initial USDC to user on origin
tx, err = originUSDCHandle.MintPublic(optsOrigin.TransactOpts, i.userWallet.Address(), realRFQAmount)
i.Nil(err)
i.originBackend.WaitForConfirmation(i.GetTestContext(), tx)
i.Approve(i.originBackend, originUSDC, i.userWallet)

// now we can send the money
_, originFastBridge := i.manager.GetFastBridgeV2(i.GetTestContext(), i.originBackend)
auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr())
// we want 499 usdc for 500 requested within a day
tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridgev2.IFastBridgeBridgeParams{
DstChainId: uint32(i.destBackend.GetChainID()),

Check failure on line 652 in services/rfq/e2e/rfq_test.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

G115: integer overflow conversion uint -> uint32 (gosec)
Sender: i.userWallet.Address(),
To: i.userWallet.Address(),
OriginToken: originUSDC.Address(),
Expand Down Expand Up @@ -670,7 +767,7 @@
return false
})

_, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend)
_, originFastBridge := i.manager.GetFastBridgeV2(i.GetTestContext(), i.originBackend)
auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr())
parser, err := fastbridge.NewParser(originFastBridge.Address())
i.NoError(err)
Comment on lines +770 to 773
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential mismatch in parser usage: using fastbridge.NewParser with FastBridgeV2

In TestConcurrentBridges, you're using fastbridge.NewParser(originFastBridge.Address()) to parse events from a FastBridgeV2 contract. This could cause parsing errors due to differences in event structures between versions. Use fastbridgev2.NewParser for FastBridgeV2 contracts.

Apply this diff to correct the parser:

-	parser, err := fastbridge.NewParser(originFastBridge.Address())
+	parser, err := fastbridgev2.NewParser(originFastBridge.Address())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
_, originFastBridge := i.manager.GetFastBridgeV2(i.GetTestContext(), i.originBackend)
auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr())
parser, err := fastbridge.NewParser(originFastBridge.Address())
i.NoError(err)
_, originFastBridge := i.manager.GetFastBridgeV2(i.GetTestContext(), i.originBackend)
auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr())
parser, err := fastbridgev2.NewParser(originFastBridge.Address())
i.NoError(err)

Expand Down
95 changes: 76 additions & 19 deletions services/rfq/e2e/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@
originBackendChainID: i.manager.Get(i.GetTestContext(), i.originBackend, testutil.FastBridgeType).Address().String(),
destBackendChainID: i.manager.Get(i.GetTestContext(), i.destBackend, testutil.FastBridgeType).Address().String(),
},
FastBridgeContractsV2: map[uint32]string{
originBackendChainID: i.manager.Get(i.GetTestContext(), i.originBackend, testutil.FastBridgeV2Type).Address().String(),
destBackendChainID: i.manager.Get(i.GetTestContext(), i.destBackend, testutil.FastBridgeV2Type).Address().String(),
},
Port: strconv.Itoa(apiPort),
}
api, err := rest.NewAPI(i.GetTestContext(), apiCfg, i.metrics, i.omniClient, apiStore)
Expand Down Expand Up @@ -147,7 +151,7 @@
// but this way we can do something while we're waiting for the other backend to startup.
// no need to wait for these to deploy since they can happen in background as soon as the backend is up.
predeployTokens := []contracts.ContractType{testutil.DAIType, testutil.USDTType, testutil.WETH9Type}
predeploys := append(predeployTokens, testutil.FastBridgeType)
predeploys := append(predeployTokens, testutil.FastBridgeV2Type)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure both FastBridge versions are deployed in setupBE

Currently, only FastBridgeV2Type is appended to predeploys. If the integration tests require both FastBridgeV1 and FastBridgeV2, consider appending both to predeploys to ensure both contracts are deployed.

Apply this diff to include both versions:

 predeployTokens := []contracts.ContractType{testutil.DAIType, testutil.USDTType, testutil.WETH9Type}
- predeploys := append(predeployTokens, testutil.FastBridgeV2Type)
+ predeploys := append(predeployTokens, testutil.FastBridgeType, testutil.FastBridgeV2Type)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
predeploys := append(predeployTokens, testutil.FastBridgeV2Type)
predeploys := append(predeployTokens, testutil.FastBridgeType, testutil.FastBridgeV2Type)

slices.Reverse(predeploys) // return fast bridge first

ethAmount := *new(big.Int).Mul(big.NewInt(params.Ether), big.NewInt(10))
Expand Down Expand Up @@ -267,15 +271,41 @@

erc20, err := ierc20.NewIERC20(token.Address(), backend)
i.Require().NoError(err, "Failed to get erc20")
_, fastBridge := i.manager.GetFastBridge(i.GetTestContext(), backend)
allowance, err := erc20.Allowance(&bind.CallOpts{Context: i.GetTestContext()}, user.Address(), fastBridge.Address())

// approve fastbridgev1
_, fastBridgeV1 := i.manager.GetFastBridge(i.GetTestContext(), backend)
allowance, err := erc20.Allowance(&bind.CallOpts{Context: i.GetTestContext()}, user.Address(), fastBridgeV1.Address())
i.Require().NoError(err, "Failed to get allowance")

if allowance.Cmp(big.NewInt(0)) == 0 {
err = retry.WithBackoff(i.GetTestContext(), func(ctx context.Context) error {
txOpts := backend.GetTxContext(ctx, user.AddressPtr())
tx, err := erc20.Approve(txOpts.TransactOpts, fastBridgeV1.Address(), core.CopyBigInt(abi.MaxUint256))
if err != nil {
return fmt.Errorf("failed to approve: %w", err)
}
backend.WaitForConfirmation(ctx, tx)
return nil
})
i.Require().NoError(err, "Failed to approve")
}

// approve fastbridgev2
_, fastBridgeV2 := i.manager.GetFastBridgeV2(i.GetTestContext(), backend)
allowance, err = erc20.Allowance(&bind.CallOpts{Context: i.GetTestContext()}, user.Address(), fastBridgeV2.Address())
i.Require().NoError(err, "Failed to get allowance")

if allowance.Cmp(big.NewInt(0)) == 0 {
txOpts := backend.GetTxContext(i.GetTestContext(), user.AddressPtr())
tx, err := erc20.Approve(txOpts.TransactOpts, fastBridge.Address(), core.CopyBigInt(abi.MaxUint256))
err = retry.WithBackoff(i.GetTestContext(), func(ctx context.Context) error {
txOpts := backend.GetTxContext(ctx, user.AddressPtr())
tx, err := erc20.Approve(txOpts.TransactOpts, fastBridgeV2.Address(), core.CopyBigInt(abi.MaxUint256))
if err != nil {
return fmt.Errorf("failed to approve: %w", err)
}
backend.WaitForConfirmation(ctx, tx)
return nil
})
i.Require().NoError(err, "Failed to approve")
backend.WaitForConfirmation(i.GetTestContext(), tx)
}
}

Expand All @@ -286,11 +316,14 @@
dsn := filet.TmpDir(i.T(), "")
cctpContractOrigin, _ := i.cctpDeployManager.GetSynapseCCTP(i.GetTestContext(), i.originBackend)
cctpContractDest, _ := i.cctpDeployManager.GetSynapseCCTP(i.GetTestContext(), i.destBackend)
rfqAddressV1Origin := i.manager.Get(i.GetTestContext(), i.originBackend, testutil.FastBridgeType).Address().String()
rfqAddressV1Dest := i.manager.Get(i.GetTestContext(), i.destBackend, testutil.FastBridgeType).Address().String()
return relconfig.Config{
// generated ex-post facto
Chains: map[int]relconfig.ChainConfig{
originBackendChainID: {
RFQAddress: i.manager.Get(i.GetTestContext(), i.originBackend, testutil.FastBridgeType).Address().String(),
RFQAddress: i.manager.Get(i.GetTestContext(), i.originBackend, testutil.FastBridgeV2Type).Address().String(),
RFQAddressV1: &rfqAddressV1Origin,
RebalanceConfigs: relconfig.RebalanceConfigs{
Synapse: &relconfig.SynapseCCTPRebalanceConfig{
SynapseCCTPAddress: cctpContractOrigin.Address().Hex(),
Expand All @@ -307,7 +340,8 @@
NativeToken: "ETH",
},
destBackendChainID: {
RFQAddress: i.manager.Get(i.GetTestContext(), i.destBackend, testutil.FastBridgeType).Address().String(),
RFQAddress: i.manager.Get(i.GetTestContext(), i.destBackend, testutil.FastBridgeV2Type).Address().String(),
RFQAddressV1: &rfqAddressV1Dest,
RebalanceConfigs: relconfig.RebalanceConfigs{
Synapse: &relconfig.SynapseCCTPRebalanceConfig{
SynapseCCTPAddress: cctpContractDest.Address().Hex(),
Expand Down Expand Up @@ -362,26 +396,38 @@
defer wg.Done()

err := retry.WithBackoff(i.GetTestContext(), func(ctx context.Context) error {
metadata, rfqContract := i.manager.GetFastBridge(i.GetTestContext(), backend)
metadataV1, rfqContractV1 := i.manager.GetFastBridge(i.GetTestContext(), backend)
txContextV1 := backend.GetTxContext(i.GetTestContext(), metadataV1.OwnerPtr())

txContext := backend.GetTxContext(i.GetTestContext(), metadata.OwnerPtr())
proverRole, err := rfqContract.PROVERROLE(&bind.CallOpts{Context: i.GetTestContext()})
relayerRole, err := rfqContractV1.RELAYERROLE(&bind.CallOpts{Context: i.GetTestContext()})

Check failure on line 402 in services/rfq/e2e/setup_test.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

ineffectual assignment to err (ineffassign)
proverRole, err := rfqContractV1.RELAYERROLE(&bind.CallOpts{Context: i.GetTestContext()})

Check failure on line 403 in services/rfq/e2e/setup_test.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

ineffectual assignment to proverRole (ineffassign)
if err != nil {
return fmt.Errorf("could not get prover role: %w", err)
}
tx, err := rfqContractV1.GrantRole(txContextV1.TransactOpts, relayerRole, i.relayerWallet.Address())
if err != nil {
return fmt.Errorf("could not grant relayer role: %w", err)
}
backend.WaitForConfirmation(i.GetTestContext(), tx)

metadataV2, rfqContractV2 := i.manager.GetFastBridgeV2(i.GetTestContext(), backend)
txContextV2 := backend.GetTxContext(i.GetTestContext(), metadataV2.OwnerPtr())

tx, err := rfqContract.GrantRole(txContext.TransactOpts, proverRole, i.relayerWallet.Address())
proverRole, err = rfqContractV2.PROVERROLE(&bind.CallOpts{Context: i.GetTestContext()})
if err != nil {
return fmt.Errorf("could not get prover role: %w", err)
}
tx, err = rfqContractV2.GrantRole(txContextV2.TransactOpts, proverRole, i.relayerWallet.Address())
if err != nil {
return fmt.Errorf("could not grant prover role: %w", err)
}
backend.WaitForConfirmation(i.GetTestContext(), tx)

quoterRole, err := rfqContract.QUOTERROLE(&bind.CallOpts{Context: i.GetTestContext()})
quoterRole, err := rfqContractV2.QUOTERROLE(&bind.CallOpts{Context: i.GetTestContext()})
if err != nil {
return fmt.Errorf("could not get quoter role: %w", err)
}

tx, err = rfqContract.GrantRole(txContext.TransactOpts, quoterRole, i.relayerWallet.Address())
tx, err = rfqContractV2.GrantRole(txContextV2.TransactOpts, quoterRole, i.relayerWallet.Address())
if err != nil {
return fmt.Errorf("could not grant quoter role: %w", err)
}
Expand Down Expand Up @@ -488,13 +534,24 @@
go func(backend backends.SimulatedTestBackend) {
defer wg.Done()

metadata, rfqContract := i.manager.GetFastBridge(i.GetTestContext(), backend)
metadataV1, rfqContractV1 := i.manager.GetFastBridge(i.GetTestContext(), backend)

txContext := backend.GetTxContext(i.GetTestContext(), metadataV1.OwnerPtr())
guardRole, err := rfqContractV1.GUARDROLE(&bind.CallOpts{Context: i.GetTestContext()})
i.NoError(err)

tx, err := rfqContractV1.GrantRole(txContext.TransactOpts, guardRole, i.guardWallet.Address())
i.NoError(err)

backend.WaitForConfirmation(i.GetTestContext(), tx)

metadataV2, rfqContractV2 := i.manager.GetFastBridgeV2(i.GetTestContext(), backend)

txContext := backend.GetTxContext(i.GetTestContext(), metadata.OwnerPtr())
guardRole, err := rfqContract.GUARDROLE(&bind.CallOpts{Context: i.GetTestContext()})
txContext = backend.GetTxContext(i.GetTestContext(), metadataV2.OwnerPtr())
guardRole, err = rfqContractV2.GUARDROLE(&bind.CallOpts{Context: i.GetTestContext()})
i.NoError(err)

tx, err := rfqContract.GrantRole(txContext.TransactOpts, guardRole, i.guardWallet.Address())
tx, err = rfqContractV2.GrantRole(txContext.TransactOpts, guardRole, i.guardWallet.Address())
i.NoError(err)

backend.WaitForConfirmation(i.GetTestContext(), tx)
Expand Down
35 changes: 27 additions & 8 deletions services/rfq/guard/guardconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ type Config struct {

// ChainConfig represents the configuration for a chain.
type ChainConfig struct {
// Bridge is the rfq bridge contract address.
// RFQAddressV1 is the legacy V1 rfq bridge contract address. OPTIONAL. Only populate if also guarding a deprecated V1 contract.
RFQAddressV1 *string `yaml:"rfq_address_v1"`
// RFQAddress is the current/latest rfq bridge contract address. REQUIRED.
RFQAddress string `yaml:"rfq_address"`
// Confirmations is the number of required confirmations.
Confirmations uint64 `yaml:"confirmations"`
Expand Down Expand Up @@ -66,12 +68,19 @@ func LoadConfig(path string) (config Config, err error) {
// Validate validates the config.
func (c Config) Validate() (err error) {
for chainID := range c.Chains {
addr, err := c.GetRFQAddress(chainID)
addrV1, err := c.GetRFQAddressV1(chainID)
if err != nil {
return fmt.Errorf("could not get rfq address: %w", err)
return fmt.Errorf("could not get v1 rfq address: %w", err)
}
if !common.IsHexAddress(addr) {
return fmt.Errorf("invalid rfq address: %s", addr)
if addrV1 != nil && !common.IsHexAddress(*addrV1) {
return fmt.Errorf("invalid rfq v1 address: %s", *addrV1)
}
addrV2, err := c.GetRFQAddressV2(chainID)
if err != nil {
return fmt.Errorf("could not get v2 rfq address: %w", err)
}
if !common.IsHexAddress(addrV2) {
return fmt.Errorf("invalid rfq v2 address: %s", addrV2)
Comment on lines +71 to +83
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add test coverage for address validation logic

The validation logic for both V1 and V2 addresses lacks test coverage. Consider adding test cases for:

  • Valid V1 and V2 addresses
  • Missing V2 address
  • Invalid hex addresses
  • Nil V1 address

Would you like me to help create comprehensive test cases for the validation logic?

Additionally, consider making error messages more descriptive:

-return fmt.Errorf("could not get v1 rfq address: %w", err)
+return fmt.Errorf("failed to retrieve RFQ V1 address for chain %d: %w", chainID, err)
-return fmt.Errorf("invalid rfq v1 address: %s", *addrV1)
+return fmt.Errorf("invalid RFQ V1 address format for chain %d: %s", chainID, *addrV1)
-return fmt.Errorf("could not get v2 rfq address: %w", err)
+return fmt.Errorf("failed to retrieve RFQ V2 address for chain %d: %w", chainID, err)
-return fmt.Errorf("invalid rfq v2 address: %s", addrV2)
+return fmt.Errorf("invalid RFQ V2 address format for chain %d: %s", chainID, addrV2)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
addrV1, err := c.GetRFQAddressV1(chainID)
if err != nil {
return fmt.Errorf("could not get rfq address: %w", err)
return fmt.Errorf("could not get v1 rfq address: %w", err)
}
if !common.IsHexAddress(addr) {
return fmt.Errorf("invalid rfq address: %s", addr)
if addrV1 != nil && !common.IsHexAddress(*addrV1) {
return fmt.Errorf("invalid rfq v1 address: %s", *addrV1)
}
addrV2, err := c.GetRFQAddressV2(chainID)
if err != nil {
return fmt.Errorf("could not get v2 rfq address: %w", err)
}
if !common.IsHexAddress(addrV2) {
return fmt.Errorf("invalid rfq v2 address: %s", addrV2)
addrV1, err := c.GetRFQAddressV1(chainID)
if err != nil {
return fmt.Errorf("failed to retrieve RFQ V1 address for chain %d: %w", chainID, err)
}
if addrV1 != nil && !common.IsHexAddress(*addrV1) {
return fmt.Errorf("invalid RFQ V1 address format for chain %d: %s", chainID, *addrV1)
}
addrV2, err := c.GetRFQAddressV2(chainID)
if err != nil {
return fmt.Errorf("failed to retrieve RFQ V2 address for chain %d: %w", chainID, err)
}
if !common.IsHexAddress(addrV2) {
return fmt.Errorf("invalid RFQ V2 address format for chain %d: %s", chainID, addrV2)
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 71-71: services/rfq/guard/guardconfig/config.go#L71
Added line #L71 was not covered by tests


[warning] 75-75: services/rfq/guard/guardconfig/config.go#L75
Added line #L75 was not covered by tests


[warning] 77-79: services/rfq/guard/guardconfig/config.go#L77-L79
Added lines #L77 - L79 were not covered by tests


[warning] 81-82: services/rfq/guard/guardconfig/config.go#L81-L82
Added lines #L81 - L82 were not covered by tests

}
}

Expand All @@ -83,11 +92,20 @@ func (c Config) GetChains() map[int]ChainConfig {
return c.Chains
}

// GetRFQAddress returns the RFQ address for the given chain.
func (c Config) GetRFQAddress(chainID int) (string, error) {
// GetRFQAddressV1 returns the RFQ address for the given chain.
func (c Config) GetRFQAddressV1(chainID int) (*string, error) {
chainCfg, ok := c.Chains[chainID]
if !ok {
return nil, fmt.Errorf("v1 chain config not found for chain %d", chainID)
}
return chainCfg.RFQAddressV1, nil
}

// GetRFQAddressV2 returns the RFQ address for the given chain.
func (c Config) GetRFQAddressV2(chainID int) (string, error) {
chainCfg, ok := c.Chains[chainID]
if !ok {
return "", fmt.Errorf("chain config not found for chain %d", chainID)
return "", fmt.Errorf("v2 chain config not found for chain %d", chainID)
}
return chainCfg.RFQAddress, nil
}
Expand Down Expand Up @@ -115,6 +133,7 @@ func NewGuardConfigFromRelayer(relayerCfg relconfig.Config) Config {
}
for chainID, chainCfg := range relayerCfg.GetChains() {
cfg.Chains[chainID] = ChainConfig{
RFQAddressV1: chainCfg.RFQAddressV1,
RFQAddress: chainCfg.RFQAddress,
Confirmations: chainCfg.FinalityConfirmations,
}
Comment on lines +136 to 139
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add test coverage for guard config creation

The NewGuardConfigFromRelayer function's handling of the new RFQAddressV1 field is untested. Consider adding test cases to verify:

  • Correct mapping of both V1 and V2 addresses
  • Proper handling of nil V1 addresses

Would you like me to help create test cases for the config creation logic?

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 136-136: services/rfq/guard/guardconfig/config.go#L136
Added line #L136 was not covered by tests

Expand Down
Loading
Loading