Skip to content

Commit

Permalink
Merge 6982d44 into 9916a14
Browse files Browse the repository at this point in the history
  • Loading branch information
dwasse authored Jul 5, 2024
2 parents 9916a14 + 6982d44 commit 47da4c8
Show file tree
Hide file tree
Showing 24 changed files with 1,592 additions and 31 deletions.
1 change: 1 addition & 0 deletions docs/bridge/docs/rfq/Relayer/Relayer.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ The relayer is configured with a yaml file. The following is an example configur
- `rebalance_interval` - How often to rebalance, formatted as (s = seconds, m = minutes, h = hours)
- `relayer_api_port` - the relayer api is used to control the relayer. <!--TODO: more info here--> This api should be secured/not public.
- `base_chain_config`: Base chain config is the default config applied for each chain if the other chains do not override it. This is covered in the chains section.
- `enable_embedded_guard` - Run a guard on the same instance.
- `chains` - each chain has a different config that overrides base_chain_config. Here are the parameters for each chain
- `rfq_address` - the address of the rfq contract on this chain. These addresses are available [here](../Contracts.md).

Expand Down
2 changes: 1 addition & 1 deletion services/cctp-relayer/external/evm-cctp-contracts
139 changes: 139 additions & 0 deletions services/rfq/e2e/rfq_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package e2e_test

import (
"fmt"
"math/big"
"testing"
"time"
Expand All @@ -19,6 +20,8 @@ import (
omnirpcClient "github.com/synapsecns/sanguine/services/omnirpc/client"
"github.com/synapsecns/sanguine/services/rfq/api/client"
"github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge"
"github.com/synapsecns/sanguine/services/rfq/guard/guarddb"
guardService "github.com/synapsecns/sanguine/services/rfq/guard/service"
"github.com/synapsecns/sanguine/services/rfq/relayer/chain"
"github.com/synapsecns/sanguine/services/rfq/relayer/reldb"
"github.com/synapsecns/sanguine/services/rfq/relayer/service"
Expand All @@ -36,9 +39,12 @@ type IntegrationSuite struct {
omniClient omnirpcClient.RPCClient
metrics metrics.Handler
store reldb.Service
guardStore guarddb.Service
apiServer string
relayer *service.Relayer
guard *guardService.Guard
relayerWallet wallet.Wallet
guardWallet wallet.Wallet
userWallet wallet.Wallet
}

Expand Down Expand Up @@ -82,6 +88,7 @@ func (i *IntegrationSuite) SetupTest() {
// setup the api server
i.setupQuoterAPI()
i.setupRelayer()
i.setupGuard()
}

// getOtherBackend gets the backend that is not the current one. This is a helper
Expand All @@ -100,6 +107,14 @@ func (i *IntegrationSuite) TestUSDCtoUSDC() {
i.T().Skip("skipping until anvil issues are fixed in CI")
}

// start the relayer and guard
go func() {
_ = i.relayer.Start(i.GetTestContext())
}()
go func() {
_ = i.guard.Start(i.GetTestContext())
}()

// load token contracts
const startAmount = 1000
const rfqAmount = 900
Expand Down Expand Up @@ -240,13 +255,29 @@ func (i *IntegrationSuite) TestUSDCtoUSDC() {
i.NoError(err)
return len(originPendingRebals) > 0
})

i.Eventually(func() bool {
// verify that the guard has marked the tx as validated
results, err := i.guardStore.GetPendingProvensByStatus(i.GetTestContext(), guarddb.Validated)
i.NoError(err)
return len(results) == 1
})
}

// nolint: cyclop
func (i *IntegrationSuite) TestETHtoETH() {
if core.GetEnvBool("CI", false) {
i.T().Skip("skipping until anvil issues are fixed in CI")
}

// start the relayer and guard
go func() {
_ = i.relayer.Start(i.GetTestContext())
}()
go func() {
_ = i.guard.Start(i.GetTestContext())
}()

// Send ETH to the relayer on destination
const initialBalance = 10
i.destBackend.FundAccount(i.GetTestContext(), i.relayerWallet.Address(), *big.NewInt(initialBalance))
Expand Down Expand Up @@ -347,4 +378,112 @@ func (i *IntegrationSuite) TestETHtoETH() {
}
return false
})

i.Eventually(func() bool {
// verify that the guard has marked the tx as validated
results, err := i.guardStore.GetPendingProvensByStatus(i.GetTestContext(), guarddb.Validated)
i.NoError(err)
return len(results) == 1
})
}

func (i *IntegrationSuite) TestDispute() {
if core.GetEnvBool("CI", false) {
i.T().Skip("skipping until anvil issues are fixed in CI")
}

// 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.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()),
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 {
rawRequest = event.Request
txID = event.TransactionId
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
}
fmt.Printf("GOT RESULTS: %v\n", results)
result, err := i.guardStore.GetPendingProvenByID(i.GetTestContext(), txID)
i.NoError(err)
return result.TxHash == fakeHash && result.Status == guarddb.Disputed && result.TransactionID == txID
})
}
107 changes: 78 additions & 29 deletions services/rfq/e2e/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ import (
"github.com/synapsecns/sanguine/services/rfq/api/db/sql"
"github.com/synapsecns/sanguine/services/rfq/api/rest"
"github.com/synapsecns/sanguine/services/rfq/contracts/ierc20"
"github.com/synapsecns/sanguine/services/rfq/guard/guardconfig"
guardConnect "github.com/synapsecns/sanguine/services/rfq/guard/guarddb/connect"
guardService "github.com/synapsecns/sanguine/services/rfq/guard/service"
"github.com/synapsecns/sanguine/services/rfq/relayer/chain"
"github.com/synapsecns/sanguine/services/rfq/relayer/relconfig"
"github.com/synapsecns/sanguine/services/rfq/relayer/reldb/connect"
Expand Down Expand Up @@ -94,6 +97,9 @@ func (i *IntegrationSuite) setupBackends() {
i.relayerWallet, err = wallet.FromRandom()
i.NoError(err)

i.guardWallet, err = wallet.FromRandom()
i.NoError(err)

i.userWallet, err = wallet.FromRandom()
i.NoError(err)

Expand Down Expand Up @@ -132,10 +138,12 @@ func (i *IntegrationSuite) setupBE(backend backends.SimulatedTestBackend) {

// store the keys
backend.Store(base.WalletToKey(i.T(), i.relayerWallet))
backend.Store(base.WalletToKey(i.T(), i.guardWallet))
backend.Store(base.WalletToKey(i.T(), i.userWallet))

// fund each of the wallets
backend.FundAccount(i.GetTestContext(), i.relayerWallet.Address(), ethAmount)
backend.FundAccount(i.GetTestContext(), i.guardWallet.Address(), ethAmount)
backend.FundAccount(i.GetTestContext(), i.userWallet.Address(), ethAmount)

go func() {
Expand All @@ -144,7 +152,7 @@ func (i *IntegrationSuite) setupBE(backend backends.SimulatedTestBackend) {

// TODO: in the case of relayer this not finishing before the test starts can lead to race conditions since
// nonce may be shared between submitter and relayer. Think about how to deal w/ this.
for _, user := range []wallet.Wallet{i.relayerWallet, i.userWallet} {
for _, user := range []wallet.Wallet{i.relayerWallet, i.guardWallet, i.userWallet} {
go func(userWallet wallet.Wallet) {
for _, token := range predeployTokens {
i.Approve(backend, i.manager.Get(i.GetTestContext(), backend, token), userWallet)
Expand Down Expand Up @@ -217,36 +225,14 @@ func (i *IntegrationSuite) Approve(backend backends.SimulatedTestBackend, token
}
}

func (i *IntegrationSuite) setupRelayer() {
// add myself as a filler
var wg sync.WaitGroup
wg.Add(2)

for _, backend := range core.ToSlice(i.originBackend, i.destBackend) {
go func(backend backends.SimulatedTestBackend) {
defer wg.Done()

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

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

tx, err := rfqContract.GrantRole(txContext.TransactOpts, relayerRole, i.relayerWallet.Address())
i.NoError(err)

backend.WaitForConfirmation(i.GetTestContext(), tx)
}(backend)
}
wg.Wait()

func (i *IntegrationSuite) getRelayerConfig() relconfig.Config {
// construct the config
relayerAPIPort, err := freeport.GetFreePort()
i.NoError(err)
dsn := filet.TmpDir(i.T(), "")
cctpContractOrigin, _ := i.cctpDeployManager.GetSynapseCCTP(i.GetTestContext(), i.originBackend)
cctpContractDest, _ := i.cctpDeployManager.GetSynapseCCTP(i.GetTestContext(), i.destBackend)
cfg := relconfig.Config{
return relconfig.Config{
// generated ex-post facto
Chains: map[int]relconfig.ChainConfig{
originBackendChainID: {
Expand Down Expand Up @@ -300,6 +286,32 @@ func (i *IntegrationSuite) setupRelayer() {
},
RebalanceInterval: 0,
}
}

func (i *IntegrationSuite) setupRelayer() {
// add myself as a filler
var wg sync.WaitGroup
wg.Add(2)

for _, backend := range core.ToSlice(i.originBackend, i.destBackend) {
go func(backend backends.SimulatedTestBackend) {
defer wg.Done()

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

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

tx, err := rfqContract.GrantRole(txContext.TransactOpts, relayerRole, i.relayerWallet.Address())
i.NoError(err)

backend.WaitForConfirmation(i.GetTestContext(), tx)
}(backend)
}
wg.Wait()

cfg := i.getRelayerConfig()

// in the first backend, we want to deploy a bunch of different tokens
// TODO: functionalize me.
Expand Down Expand Up @@ -374,15 +386,52 @@ func (i *IntegrationSuite) setupRelayer() {
fmt.Sprintf("%d-%s", originBackendChainID, chain.EthAddress),
}

// TODO: good chance we wanna leave actually starting this up to the indiividual test.
var err error
i.relayer, err = service.NewRelayer(i.GetTestContext(), i.metrics, cfg)
i.NoError(err)
go func() {
err = i.relayer.Start(i.GetTestContext())
}()

dbType, err := dbcommon.DBTypeFromString(cfg.Database.Type)
i.NoError(err)
i.store, err = connect.Connect(i.GetTestContext(), dbType, cfg.Database.DSN, i.metrics)
i.NoError(err)
}

func (i *IntegrationSuite) setupGuard() {
// add myself as a guard
var wg sync.WaitGroup
wg.Add(2)

for _, backend := range core.ToSlice(i.originBackend, i.destBackend) {
go func(backend backends.SimulatedTestBackend) {
defer wg.Done()

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

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

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

backend.WaitForConfirmation(i.GetTestContext(), tx)
}(backend)
}
wg.Wait()

relayerCfg := i.getRelayerConfig()
guardCfg := guardconfig.NewGuardConfigFromRelayer(relayerCfg)
guardCfg.Signer = signerConfig.SignerConfig{
Type: signerConfig.FileType.String(),
File: filet.TmpFile(i.T(), "", i.guardWallet.PrivateKeyHex()).Name(),
}

var err error
i.guard, err = guardService.NewGuard(i.GetTestContext(), i.metrics, guardCfg, nil)
i.NoError(err)

dbType, err := dbcommon.DBTypeFromString(guardCfg.Database.Type)
i.NoError(err)
i.guardStore, err = guardConnect.Connect(i.GetTestContext(), dbType, guardCfg.Database.DSN, i.metrics)
i.NoError(err)
}
Loading

0 comments on commit 47da4c8

Please sign in to comment.