// not how this is always scoped outside of the package itself package relayer_test import ( "fmt" "math/big" "testing" "github.com/synapsecns/sanguine/core" "github.com/synapsecns/sanguine/services/cctp-relayer/db/sql/base" "github.com/synapsecns/sanguine/services/cctp-relayer/db/sql/sqlite" "github.com/Flaque/filet" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" "github.com/stretchr/testify/suite" "github.com/synapsecns/sanguine/core/metrics" "github.com/synapsecns/sanguine/core/metrics/localmetrics" "github.com/synapsecns/sanguine/core/testsuite" "github.com/synapsecns/sanguine/ethergo/backends" "github.com/synapsecns/sanguine/ethergo/backends/geth" signerConfig "github.com/synapsecns/sanguine/ethergo/signer/config" "github.com/synapsecns/sanguine/ethergo/signer/wallet" "github.com/synapsecns/sanguine/services/cctp-relayer/config" "github.com/synapsecns/sanguine/services/cctp-relayer/metadata" cctpTest "github.com/synapsecns/sanguine/services/cctp-relayer/testutil" omnirpcHelper "github.com/synapsecns/sanguine/services/omnirpc/testhelper" "golang.org/x/sync/errgroup" ) // TestHelperSuite defines the basic test suite. type CCTPRelayerSuite struct { *testsuite.TestSuite // testBackends contains a list of all test backends testBackends []backends.SimulatedTestBackend // we'll use this later deployManager *cctpTest.DeployManager // testOmnirpc setup in SetupTest testOmnirpc string // metricsHandler is the metrics handler for the test metricsHandler metrics.Handler // testStore is the test store for the test testStore *base.Store // testWallet is the test wallet for the test testWallet wallet.Wallet } // NewTestSuite creates a new test suite. func NewTestSuite(tb testing.TB) *CCTPRelayerSuite { tb.Helper() return &CCTPRelayerSuite{ TestSuite: testsuite.NewTestSuite(tb), } } func (s *CCTPRelayerSuite) SetupSuite() { s.TestSuite.SetupSuite() // for tracing localmetrics.SetupTestJaeger(s.GetSuiteContext(), s.T()) // let's create 2 mock chains chainIDs := []uint64{1, 43114} // preallocate a slice for testbackends to the size of chainIDs // this way we can avoid non-deterministic order + needing to acquire/release a lock s.testBackends = make([]backends.SimulatedTestBackend, len(chainIDs)) g, _ := errgroup.WithContext(s.GetSuiteContext()) for i, chainID := range chainIDs { pos := i // get position of chain id in array chainID := chainID // capture func literal g.Go(func() error { // we need to use the embedded backend here, because the simulated backend doesn't support rpcs required by scribe backend := geth.NewEmbeddedBackendForChainID(s.GetSuiteContext(), s.T(), new(big.Int).SetUint64(chainID)) // add the backend to the list of backends s.testBackends[pos] = backend return nil }) } // wait for all backends to be ready if err := g.Wait(); err != nil { s.T().Fatal(err) } // fund test wallet with ether var err error s.testWallet, err = wallet.FromRandom() s.Nil(err) for _, backend := range s.testBackends { backend.FundAccount(s.GetSuiteContext(), s.testWallet.Address(), *big.NewInt(params.Ether)) } } // TODO: there should be a way to do this in the deployer, this probably involves making the concept of a contract-registry // multi-chain (possibly by wrapping the registry). This would allow the use of setting remotes in the deployer itself rather than here. func (s *CCTPRelayerSuite) registerRemoteDeployments() { for _, backend := range s.testBackends { cctpContract, cctpHandle := s.deployManager.GetSynapseCCTP(s.GetTestContext(), backend) _, tokenMessengeHandle := s.deployManager.GetMockTokenMessengerType(s.GetTestContext(), backend) // on the above contract, set the remote for each backend for _, backendToSetFrom := range s.testBackends { // we don't need to set the backends own remote! if backendToSetFrom.GetChainID() == backend.GetChainID() { continue } remoteCCTP, _ := s.deployManager.GetSynapseCCTP(s.GetTestContext(), backendToSetFrom) remoteMessenger, _ := s.deployManager.GetMockTokenMessengerType(s.GetTestContext(), backendToSetFrom) txOpts := backend.GetTxContext(s.GetTestContext(), cctpContract.OwnerPtr()) // set the remote cctp contract on this cctp contract // TODO: verify chainID / domain are correct remoteDomain := cctpTest.ChainIDDomainMap[uint32(remoteCCTP.ChainID().Int64())] tx, err := cctpHandle.SetRemoteDomainConfig(txOpts.TransactOpts, big.NewInt(remoteCCTP.ChainID().Int64()), remoteDomain, remoteCCTP.Address()) s.Require().NoError(err) backend.WaitForConfirmation(s.GetTestContext(), tx) // register the remote token messenger on the tokenMessenger contract _, err = tokenMessengeHandle.SetRemoteTokenMessenger(txOpts.TransactOpts, uint32(backendToSetFrom.GetChainID()), addressToBytes32(remoteMessenger.Address())) s.Nil(err) } } } // CCTPPrefix is the prefix for all CCTP tokens. const CCTPPrefix = "CCTP." func (s *CCTPRelayerSuite) registerTokens() { for _, backend := range s.testBackends { _, tokenHandle := s.deployManager.GetMockMintBurnTokenType(s.GetTestContext(), backend) cctpContract, cctpHandle := s.deployManager.GetSynapseCCTP(s.GetTestContext(), backend) txOpts := backend.GetTxContext(s.GetTestContext(), cctpContract.OwnerPtr()) tx, err := cctpHandle.AddToken(txOpts.TransactOpts, fmt.Sprintf("%sUSDC", CCTPPrefix), tokenHandle.Address(), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0)) s.Require().NoError(err) backend.WaitForConfirmation(s.GetTestContext(), tx) } } // addressToBytes32 converts an address to a bytes32. func addressToBytes32(addr common.Address) [32]byte { var buf [32]byte copy(buf[:], addr[:]) return buf } func (s *CCTPRelayerSuite) SetupTest() { s.TestSuite.SetupTest() s.deployManager = cctpTest.NewDeployManager(s.T()) // create the test omnirpc backend s.testOmnirpc = omnirpcHelper.NewOmnirpcServer(s.GetTestContext(), s.T(), s.testBackends...) // create the test metrics handler var err error // don't use metrics on ci for integration tests isCI := core.GetEnvBool("CI", false) useMetrics := !isCI metricsHandler := metrics.Null if useMetrics { localmetrics.SetupTestJaeger(s.GetSuiteContext(), s.T()) metricsHandler = metrics.Jaeger } s.metricsHandler, err = metrics.NewByType(s.GetTestContext(), metadata.BuildInfo(), metricsHandler) s.Require().NoError(err) // create the test store path := filet.TmpDir(s.T(), "") db, err := sqlite.NewSqliteStore(s.GetTestContext(), path, s.metricsHandler, false) s.Require().NoError(err) s.testStore = base.NewStore(db.DB(), s.metricsHandler) // deploy the contract to all backends s.deployManager.BulkDeploy(s.GetTestContext(), s.testBackends, cctpTest.SynapseCCTPType, cctpTest.MockMintBurnTokenType) s.registerRemoteDeployments() s.registerTokens() } func (s *CCTPRelayerSuite) GetTestConfig() config.Config { cfg := config.Config{ BaseOmnirpcURL: s.testOmnirpc, // BaseOmnirpcURL: s.testBackends[0].RPCAddress(), Signer: signerConfig.SignerConfig{ Type: signerConfig.FileType.String(), File: filet.TmpFile(s.T(), "", s.testWallet.PrivateKeyHex()).Name(), }, CCTPType: "synapse", } chains := []config.ChainConfig{} for _, backend := range s.testBackends { _, handle := s.deployManager.GetSynapseCCTP(s.GetTestContext(), backend) chains = append(chains, config.ChainConfig{ ChainID: uint32(backend.GetChainID()), CCTPAddress: handle.Address().String(), }) } cfg.Chains = chains return cfg } func TestCCTPRelayerSuite(t *testing.T) { suite.Run(t, NewTestSuite(t)) }