diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..c9b89af --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,34 @@ +name: Lint +on: + push: + branches: + - main + paths: + - "**/*.go" + - "go.mod" + - "go.sum" + - "**/go.mod" + - "**/go.sum" + pull_request: + paths: + - "**/*.go" + - "go.mod" + - "go.sum" + - "**/go.mod" + - "**/go.sum" + merge_group: +permissions: + contents: read +jobs: + golangci: + name: golangci-lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.21" + check-latest: true + - name: run linting + run: | + make lint \ No newline at end of file diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..20af873 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,65 @@ +run: + timeout: 10m + tests: true + +linters: + disable-all: true + enable: + - asciicheck + - bidichk + - bodyclose + - decorder + - dupl + - dupword + - errcheck + - errchkjson + - errname + - exhaustive + - exportloopref + - forbidigo + - gci + - goconst + - gocritic + - gofmt + - gosec + - gosimple + - gosmopolitan + - govet + - grouper + - ineffassign + - loggercheck + - misspell + - nilerr + - nilnil + - noctx + - stylecheck + - testifylint + - thelper + - tparallel + - typecheck + - unconvert + - unparam + - unused + - usestdlibvars + - wastedassign + - whitespace + +linters-settings: + gci: + custom-order: true + sections: + - standard # Standard section: captures all standard packages. + - default # Default section: contains all imports that could not be matched to another section type. + - blank # blank imports + - dot # dot imports + - prefix(github.com/cometbft/cometbft) + - prefix(github.com/cosmos) + - prefix(github.com/cosmos/cosmos-sdk) + - prefix(cosmossdk.io) + - prefix(github.com/strangelove-ventures/noble-cctp-relayer) + gosec: + excludes: + - G404 + +issues: + max-issues-per-linter: 0 \ No newline at end of file diff --git a/Makefile b/Makefile index 371392e..28b78d6 100644 --- a/Makefile +++ b/Makefile @@ -17,20 +17,20 @@ GOBIN := $(GOPATH)/bin ############################################################################### ### Formatting & Linting ### ############################################################################### -.PHONY: format lint +.PHONY: lint lint-fix -gofumpt_cmd=mvdan.cc/gofumpt -golangci_lint_cmd=github.com/golangci/golangci-lint/cmd/golangci-lint - -format: - @echo "🤖 Running formatter..." - @go run $(gofumpt_cmd) -l -w . - @echo "✅ Completed formatting!" +golangci_lint_cmd=golangci-lint +golangci_version=v1.57.2 lint: - @echo "🤖 Running linter..." - @go run $(golangci_lint_cmd) run --timeout=10m - @echo "✅ Completed linting!" + @echo "--> Running linter" + @go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(golangci_version) + @$(golangci_lint_cmd) run ./... --timeout 15m + +lint-fix: + @echo "--> Running linter and fixing issues" + @go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(golangci_version) + @$(golangci_lint_cmd) run ./... --fix --timeout 15m ############################################################################### diff --git a/circle/attestation.go b/circle/attestation.go index ca069fc..4776798 100644 --- a/circle/attestation.go +++ b/circle/attestation.go @@ -1,6 +1,7 @@ package circle import ( + "context" "encoding/json" "fmt" "io" @@ -8,20 +9,41 @@ import ( "time" "cosmossdk.io/log" + "github.com/strangelove-ventures/noble-cctp-relayer/types" ) // CheckAttestation checks the iris api for attestation status and returns true if attestation is complete -func CheckAttestation(attestationURL string, logger log.Logger, irisLookupId string, txHash string, sourceDomain, destDomain types.Domain) *types.AttestationResponse { - logger.Debug(fmt.Sprintf("Checking attestation for %s%s%s for source tx %s from %d to %d", attestationURL, "0x", irisLookupId, txHash, sourceDomain, destDomain)) +func CheckAttestation(attestationURL string, logger log.Logger, irisLookupID string, txHash string, sourceDomain, destDomain types.Domain) *types.AttestationResponse { + logger.Debug(fmt.Sprintf("Checking attestation for %s%s%s for source tx %s from %d to %d", attestationURL, "0x", irisLookupID, txHash, sourceDomain, destDomain)) client := http.Client{Timeout: 2 * time.Second} - rawResponse, err := client.Get(attestationURL + "0x" + irisLookupId) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // append ending / if not present + if attestationURL[len(attestationURL)-1:] != "/" { + attestationURL += "/" + } + + // add 0x prefix if not present + if len(irisLookupID) > 2 && irisLookupID[:2] != "0x" { + irisLookupID = "0x" + irisLookupID + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, attestationURL+irisLookupID, nil) + if err != nil { + logger.Debug("error creating request: " + err.Error()) + return nil + } + + rawResponse, err := client.Do(req) if err != nil { logger.Debug("error during request: " + err.Error()) return nil } + defer rawResponse.Body.Close() if rawResponse.StatusCode != http.StatusOK { logger.Debug("non 200 response received from Circles attestation API") return nil @@ -38,7 +60,7 @@ func CheckAttestation(attestationURL string, logger log.Logger, irisLookupId str logger.Debug("unable to unmarshal response") return nil } - logger.Info(fmt.Sprintf("Attestation found for %s%s%s", attestationURL, "0x", irisLookupId)) + logger.Info(fmt.Sprintf("Attestation found for %s%s%s", attestationURL, "0x", irisLookupID)) return &response } diff --git a/circle/attestation_test.go b/circle/attestation_test.go index a2fa252..8f19199 100644 --- a/circle/attestation_test.go +++ b/circle/attestation_test.go @@ -4,28 +4,47 @@ import ( "os" "testing" - "cosmossdk.io/log" "github.com/rs/zerolog" + "github.com/stretchr/testify/require" + + "cosmossdk.io/log" + "github.com/strangelove-ventures/noble-cctp-relayer/circle" "github.com/strangelove-ventures/noble-cctp-relayer/types" - "github.com/stretchr/testify/require" ) var cfg types.Config var logger log.Logger func init() { - cfg.Circle.AttestationBaseUrl = "https://iris-api-sandbox.circle.com/attestations/" + cfg.Circle.AttestationBaseURL = "https://iris-api-sandbox.circle.com/attestations/" logger = log.NewLogger(os.Stdout, log.LevelOption(zerolog.ErrorLevel)) } func TestAttestationIsReady(t *testing.T) { - resp := circle.CheckAttestation(cfg.Circle.AttestationBaseUrl, logger, "85bbf7e65a5992e6317a61f005e06d9972a033d71b514be183b179e1b47723fe", "", 0, 4) + resp := circle.CheckAttestation(cfg.Circle.AttestationBaseURL, logger, "85bbf7e65a5992e6317a61f005e06d9972a033d71b514be183b179e1b47723fe", "", 0, 4) require.NotNil(t, resp) require.Equal(t, "complete", resp.Status) } func TestAttestationNotFound(t *testing.T) { - resp := circle.CheckAttestation(cfg.Circle.AttestationBaseUrl, logger, "not an attestation", "", 0, 4) + resp := circle.CheckAttestation(cfg.Circle.AttestationBaseURL, logger, "not an attestation", "", 0, 4) require.Nil(t, resp) } + +func TestAttestationWithoutEndingSlash(t *testing.T) { + startURL := cfg.Circle.AttestationBaseURL + cfg.Circle.AttestationBaseURL = startURL[:len(startURL)-1] + + resp := circle.CheckAttestation(cfg.Circle.AttestationBaseURL, logger, "85bbf7e65a5992e6317a61f005e06d9972a033d71b514be183b179e1b47723fe", "", 0, 4) + require.NotNil(t, resp) + require.Equal(t, "complete", resp.Status) + + cfg.Circle.AttestationBaseURL = startURL +} + +func TestAttestationWithLeading0x(t *testing.T) { + resp := circle.CheckAttestation(cfg.Circle.AttestationBaseURL, logger, "0x85bbf7e65a5992e6317a61f005e06d9972a033d71b514be183b179e1b47723fe", "", 0, 4) + require.NotNil(t, resp) + require.Equal(t, "complete", resp.Status) +} diff --git a/cmd/appstate.go b/cmd/appstate.go index b41f079..689f88a 100644 --- a/cmd/appstate.go +++ b/cmd/appstate.go @@ -3,8 +3,10 @@ package cmd import ( "os" - "cosmossdk.io/log" "github.com/rs/zerolog" + + "cosmossdk.io/log" + "github.com/strangelove-ventures/noble-cctp-relayer/types" ) @@ -73,7 +75,7 @@ func (a *AppState) loadConfigFile() { // validateConfig checks the AppState Config for any invalid settings. func (a *AppState) validateConfig() { - if a.Config.Circle.AttestationBaseUrl == "" { + if a.Config.Circle.AttestationBaseURL == "" { a.Logger.Error("AttestationBaseUrl is required in the config") os.Exit(1) } diff --git a/cmd/config.go b/cmd/config.go index 3f878ee..e65df88 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -7,10 +7,11 @@ import ( "strings" "github.com/spf13/cobra" + "gopkg.in/yaml.v2" + "github.com/strangelove-ventures/noble-cctp-relayer/ethereum" "github.com/strangelove-ventures/noble-cctp-relayer/noble" "github.com/strangelove-ventures/noble-cctp-relayer/types" - "gopkg.in/yaml.v2" ) // Command for printing current configuration @@ -26,7 +27,6 @@ func configShowCmd(a *AppState) *cobra.Command { $ %s show-config --config %s $ %s sc`, appName, defaultConfigPath, appName)), RunE: func(cmd *cobra.Command, args []string) error { - jsn, err := cmd.Flags().GetBool(flagJSON) if err != nil { return err @@ -50,8 +50,7 @@ $ %s sc`, appName, defaultConfigPath, appName)), } }, } - addJsonFlag(cmd) - return cmd + return addJSONFlag(cmd) } // ParseConfig parses the app config file @@ -70,7 +69,7 @@ func ParseConfig(file string) (*types.Config, error) { EnabledRoutes: cfg.EnabledRoutes, Circle: cfg.Circle, ProcessorWorkerCount: cfg.ProcessorWorkerCount, - Api: cfg.Api, + API: cfg.API, Chains: make(map[string]types.ChainConfig), } diff --git a/cmd/config_test.go b/cmd/config_test.go index ab714e2..5cea3b6 100644 --- a/cmd/config_test.go +++ b/cmd/config_test.go @@ -3,10 +3,11 @@ package cmd_test import ( "testing" + "github.com/stretchr/testify/require" + "github.com/strangelove-ventures/noble-cctp-relayer/cmd" "github.com/strangelove-ventures/noble-cctp-relayer/ethereum" "github.com/strangelove-ventures/noble-cctp-relayer/noble" - "github.com/stretchr/testify/require" ) func TestConfig(t *testing.T) { diff --git a/cmd/flags.go b/cmd/flags.go index 5bc3cbc..b6c80b0 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -22,10 +22,9 @@ func addAppPersistantFlags(cmd *cobra.Command, a *AppState) *cobra.Command { cmd.PersistentFlags().Int16P(flagMetricsPort, "p", 2112, "customize Prometheus metrics port") cmd.PersistentFlags().DurationP(flagFlushInterval, "i", 0, "how frequently should a flush routine be run") return cmd - } -func addJsonFlag(cmd *cobra.Command) *cobra.Command { +func addJSONFlag(cmd *cobra.Command) *cobra.Command { cmd.Flags().Bool(flagJSON, false, "return in json format") return cmd } diff --git a/cmd/process.go b/cmd/process.go index ae7a3f9..3f499f1 100644 --- a/cmd/process.go +++ b/cmd/process.go @@ -8,11 +8,13 @@ import ( "strconv" "time" - "cosmossdk.io/log" - "cosmossdk.io/math" cctptypes "github.com/circlefin/noble-cctp/x/cctp/types" "github.com/gin-gonic/gin" "github.com/spf13/cobra" + + "cosmossdk.io/log" + "cosmossdk.io/math" + "github.com/strangelove-ventures/noble-cctp-relayer/circle" "github.com/strangelove-ventures/noble-cctp-relayer/ethereum" "github.com/strangelove-ventures/noble-cctp-relayer/noble" @@ -37,11 +39,10 @@ func Start(a *AppState) *cobra.Command { a.InitAppState() }, Run: func(cmd *cobra.Command, args []string) { - logger := a.Logger cfg := a.Config - go startApi(a) + go startAPI(a) // messageState processing queue var processingQueue = make(chan *types.TxState, 10000) @@ -117,8 +118,11 @@ func Start(a *AppState) *cobra.Command { defer func() { for _, c := range registeredDomains { - fmt.Printf("\n%s: latest-block: %d last-flushed-block: %d", c.Name(), c.LatestBlock(), c.LastFlushedBlock()) - c.CloseClients() + logger.Info(fmt.Sprintf("%s: latest-block: %d last-flushed-block: %d", c.Name(), c.LatestBlock(), c.LastFlushedBlock())) + err := c.CloseClients() + if err != nil { + logger.Error("Error closing clients", "error", err) + } } }() @@ -157,7 +161,6 @@ func StartProcessor( var broadcastMsgs = make(map[types.Domain][]*types.MessageState) var requeue bool for _, msg := range tx.Msgs { - // if a filter's condition is met, mark as filtered if FilterDisabledCCTPRoutes(cfg, logger, msg) || filterInvalidDestinationCallers(registeredDomains, logger, msg) || @@ -169,32 +172,35 @@ func StartProcessor( // if the message is burned or pending, check for an attestation if msg.Status == types.Created || msg.Status == types.Pending { - response := circle.CheckAttestation(cfg.Circle.AttestationBaseUrl, logger, msg.IrisLookupId, msg.SourceTxHash, msg.SourceDomain, msg.DestDomain) + response := circle.CheckAttestation(cfg.Circle.AttestationBaseURL, logger, msg.IrisLookupID, msg.SourceTxHash, msg.SourceDomain, msg.DestDomain) - if response == nil { - logger.Debug("Attestation is still processing for 0x" + msg.IrisLookupId + ". Retrying...") + switch { + case response == nil: + logger.Debug("Attestation is still processing for 0x" + msg.IrisLookupID + ". Retrying...") requeue = true continue - } else if msg.Status == types.Created && response.Status == "pending_confirmations" { - logger.Debug("Attestation is created but still pending confirmations for 0x" + msg.IrisLookupId + ". Retrying...") + case msg.Status == types.Created && response.Status == "pending_confirmations": + logger.Debug("Attestation is created but still pending confirmations for 0x" + msg.IrisLookupID + ". Retrying...") State.Mu.Lock() msg.Status = types.Pending msg.Updated = time.Now() State.Mu.Unlock() requeue = true continue - } else if response.Status == "pending_confirmations" { - logger.Debug("Attestation is still pending for 0x" + msg.IrisLookupId + ". Retrying...") + case response.Status == "pending_confirmations": + logger.Debug("Attestation is still pending for 0x" + msg.IrisLookupID + ". Retrying...") requeue = true continue - } else if response.Status == "complete" { - logger.Debug("Attestation is complete for 0x" + msg.IrisLookupId + ".") + case response.Status == "complete": + logger.Debug("Attestation is complete for 0x" + msg.IrisLookupID + ".") State.Mu.Lock() msg.Status = types.Attested msg.Attestation = response.Attestation msg.Updated = time.Now() broadcastMsgs[msg.DestDomain] = append(broadcastMsgs[msg.DestDomain], msg) State.Mu.Unlock() + default: + logger.Error("Attestation failed for unknown reason for 0x" + msg.IrisLookupID + ". Status: " + response.Status) } } } @@ -250,7 +256,6 @@ func FilterDisabledCCTPRoutes(cfg *types.Config, logger log.Logger, msg *types.M logger.Info(fmt.Sprintf("Filtered tx %s because relaying from %d to %d is not enabled", msg.SourceTxHash, msg.SourceDomain, msg.DestDomain)) return true - } // filterInvalidDestinationCallers returns true if the minter is not the destination caller for the specified domain @@ -317,20 +322,24 @@ func filterLowTransfers(cfg *types.Config, logger log.Logger, msg *types.Message return false } -func startApi(a *AppState) { +func startAPI(a *AppState) { logger := a.Logger cfg := a.Config gin.SetMode(gin.ReleaseMode) router := gin.Default() - err := router.SetTrustedProxies(cfg.Api.TrustedProxies) // vpn.primary.strange.love + err := router.SetTrustedProxies(cfg.API.TrustedProxies) // vpn.primary.strange.love if err != nil { logger.Error("Unable to set trusted proxies on API server: " + err.Error()) os.Exit(1) } router.GET("/tx/:txHash", getTxByHash) - router.Run("localhost:8000") + err = router.Run("localhost:8000") + if err != nil { + logger.Error("Unable to start API server: " + err.Error()) + os.Exit(1) + } } func getTxByHash(c *gin.Context) { diff --git a/cmd/process_test.go b/cmd/process_test.go index 307d16f..743a3f5 100644 --- a/cmd/process_test.go +++ b/cmd/process_test.go @@ -6,12 +6,14 @@ import ( "testing" "time" - "cosmossdk.io/log" "github.com/rs/zerolog" + "github.com/stretchr/testify/require" + + "cosmossdk.io/log" + "github.com/strangelove-ventures/noble-cctp-relayer/cmd" testutil "github.com/strangelove-ventures/noble-cctp-relayer/test_util" "github.com/strangelove-ventures/noble-cctp-relayer/types" - "github.com/stretchr/testify/require" ) // var a *cmd.AppState @@ -64,10 +66,10 @@ func TestProcessDisabledCctpRoute(t *testing.T) { Msgs: []*types.MessageState{ { SourceTxHash: "123", - IrisLookupId: "a404f4155166a1fc7ffee145b5cac6d0f798333745289ab1db171344e226ef0c", + IrisLookupID: "a404f4155166a1fc7ffee145b5cac6d0f798333745289ab1db171344e226ef0c", Status: types.Created, SourceDomain: 0, - DestDomain: 5, //not configured + DestDomain: 5, // not configured DestinationCaller: emptyBz, }, }, @@ -99,7 +101,7 @@ func TestProcessInvalidDestinationCaller(t *testing.T) { Msgs: []*types.MessageState{ { SourceTxHash: "123", - IrisLookupId: "a404f4155166a1fc7ffee145b5cac6d0f798333745289ab1db171344e226ef0c", + IrisLookupID: "a404f4155166a1fc7ffee145b5cac6d0f798333745289ab1db171344e226ef0c", Status: types.Created, SourceDomain: 0, DestDomain: 4, @@ -119,7 +121,6 @@ func TestProcessInvalidDestinationCaller(t *testing.T) { // we want to filter out the transaction if the route is not enabled func TestFilterDisabledCCTPRoutes(t *testing.T) { - logger := log.NewLogger(os.Stdout, log.LevelOption(zerolog.DebugLevel)) var msgState types.MessageState @@ -153,5 +154,4 @@ func TestFilterDisabledCCTPRoutes(t *testing.T) { } filterTx = cmd.FilterDisabledCCTPRoutes(&cfg, logger, &msgState) require.True(t, filterTx) - } diff --git a/cmd/version.go b/cmd/version.go index 2dbc4fd..5269cb5 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -34,7 +34,6 @@ $ %s v`, appName, appName, )), RunE: func(cmd *cobra.Command, args []string) error { - jsn, err := cmd.Flags().GetBool(flagJSON) if err != nil { return err @@ -62,6 +61,5 @@ $ %s v`, return err }, } - addJsonFlag(versionCmd) - return versionCmd + return addJSONFlag(versionCmd) } diff --git a/cosmos/codec.go b/cosmos/codec.go index 6ac6f0d..6f92cf3 100644 --- a/cosmos/codec.go +++ b/cosmos/codec.go @@ -2,6 +2,7 @@ package cosmos import ( "github.com/circlefin/noble-cctp/x/cctp" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" @@ -9,8 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/tx" - // authz "github.com/cosmos/cosmos-sdk/x/authz/module" - //"github.com/cosmos/cosmos-sdk/x/bank" ) var ModuleBasics = []module.AppModuleBasic{ diff --git a/cosmos/cosmosprovider.go b/cosmos/cosmosprovider.go index 39495a7..9693926 100644 --- a/cosmos/cosmosprovider.go +++ b/cosmos/cosmosprovider.go @@ -3,13 +3,14 @@ package cosmos import ( "time" + "google.golang.org/grpc/encoding" + "google.golang.org/grpc/encoding/proto" + rpcclient "github.com/cometbft/cometbft/rpc/client" rpchttp "github.com/cometbft/cometbft/rpc/client/http" libclient "github.com/cometbft/cometbft/rpc/jsonrpc/client" - gogogrpc "github.com/cosmos/gogoproto/grpc" - "google.golang.org/grpc/encoding" - "google.golang.org/grpc/encoding/proto" + gogogrpc "github.com/cosmos/gogoproto/grpc" ) var _ gogogrpc.ClientConn = &CosmosProvider{} diff --git a/cosmos/grpc_shim.go b/cosmos/grpc_shim.go index 008985a..d4563f9 100644 --- a/cosmos/grpc_shim.go +++ b/cosmos/grpc_shim.go @@ -6,14 +6,16 @@ import ( "reflect" "strconv" - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/cosmos-sdk/codec/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" + + abci "github.com/cometbft/cometbft/abci/types" + + "github.com/cosmos/cosmos-sdk/codec/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" ) // Invoke implements the grpc ClientConn.Invoke method @@ -86,7 +88,6 @@ func (cc *CosmosProvider) runGRPCQuery(ctx context.Context, method string, req i return abci.ResponseQuery{}, nil, sdkerrors.ErrInvalidRequest.Wrapf( "client.Context.Invoke: height (%d) from %q must be >= 0", height, grpctypes.GRPCBlockHeightHeader) } - } height, err := heightFromMetadata(md) diff --git a/cosmos/query.go b/cosmos/query.go index 448d728..7d25c20 100644 --- a/cosmos/query.go +++ b/cosmos/query.go @@ -5,9 +5,11 @@ import ( "fmt" cctptypes "github.com/circlefin/noble-cctp/x/cctp/types" + abci "github.com/cometbft/cometbft/abci/types" rpcclient "github.com/cometbft/cometbft/rpc/client" coretypes "github.com/cometbft/cometbft/rpc/core/types" + "github.com/strangelove-ventures/noble-cctp-relayer/types" ) diff --git a/cosmos/query_test.go b/cosmos/query_test.go index 0ecd20f..3d89629 100644 --- a/cosmos/query_test.go +++ b/cosmos/query_test.go @@ -4,8 +4,9 @@ import ( "context" "testing" - "github.com/strangelove-ventures/noble-cctp-relayer/cosmos" "github.com/stretchr/testify/require" + + "github.com/strangelove-ventures/noble-cctp-relayer/cosmos" ) func TestUsedNonce(t *testing.T) { diff --git a/ethereum/broadcast.go b/ethereum/broadcast.go index 052ab66..91372b4 100644 --- a/ethereum/broadcast.go +++ b/ethereum/broadcast.go @@ -10,10 +10,12 @@ import ( "strconv" "time" - "cosmossdk.io/log" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + + "cosmossdk.io/log" + "github.com/strangelove-ventures/noble-cctp-relayer/ethereum/contracts" "github.com/strangelove-ventures/noble-cctp-relayer/relayer" "github.com/strangelove-ventures/noble-cctp-relayer/types" @@ -40,7 +42,6 @@ func (e *Ethereum) Broadcast( sequenceMap *types.SequenceMap, m *relayer.PromMetrics, ) error { - logger = logger.With("chain", e.name, "chain_id", e.chainID, "domain", e.domain) backend := NewContractBackendWrapper(e.rpcClient) @@ -144,14 +145,12 @@ func (e *Ethereum) attemptBroadcast( response, nonceErr := messageTransmitter.UsedNonces(co, [32]byte(crypto.Keccak256(key))) if nonceErr != nil { logger.Debug("Error querying whether nonce was used. Continuing...", "error:", nonceErr) - } else { - if response.Uint64() == uint64(1) { - // nonce has already been used, mark as complete - logger.Debug(fmt.Sprintf("This source domain/nonce has already been used: %d %d", - msg.SourceDomain, msg.Nonce), "src-tx", msg.SourceTxHash, "reviever") - msg.Status = types.Complete - return nil - } + } else if response.Uint64() == uint64(1) { + // nonce has already been used, mark as complete + logger.Debug(fmt.Sprintf("This source domain/nonce has already been used: %d %d", + msg.SourceDomain, msg.Nonce), "src-tx", msg.SourceTxHash, "reviever") + msg.Status = types.Complete + return nil } // broadcast txn @@ -171,7 +170,7 @@ func (e *Ethereum) attemptBroadcast( } logger.Error(fmt.Sprintf("error during broadcast: %s", err.Error())) - if parsedErr, ok := err.(JsonError); ok { + if parsedErr, ok := err.(JSONError); ok { if parsedErr.ErrorCode() == 3 && parsedErr.Error() == "execution reverted: Nonce already used" { msg.Status = types.Complete logger.Error(fmt.Sprintf("This account nonce has already been used: %d", nonce)) diff --git a/ethereum/broadcast_test.go b/ethereum/broadcast_test.go index f39e596..ff09e7c 100644 --- a/ethereum/broadcast_test.go +++ b/ethereum/broadcast_test.go @@ -11,9 +11,10 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/joho/godotenv" + "github.com/stretchr/testify/require" + "github.com/strangelove-ventures/noble-cctp-relayer/ethereum/contracts" testutil "github.com/strangelove-ventures/noble-cctp-relayer/test_util" - "github.com/stretchr/testify/require" ) func TestEthUsedNonce(t *testing.T) { diff --git a/ethereum/chain.go b/ethereum/chain.go index 1effa87..8b7ddfd 100644 --- a/ethereum/chain.go +++ b/ethereum/chain.go @@ -10,9 +10,10 @@ import ( "strings" "sync" + "github.com/ethereum/go-ethereum/ethclient" + "cosmossdk.io/log" - "github.com/ethereum/go-ethereum/ethclient" "github.com/strangelove-ventures/noble-cctp-relayer/types" ) @@ -145,11 +146,12 @@ func (e *Ethereum) InitializeClients(ctx context.Context, logger log.Logger) err return nil } -func (e *Ethereum) CloseClients() { +func (e *Ethereum) CloseClients() error { if e.wsClient != nil { e.wsClient.Close() } if e.rpcClient != nil { e.rpcClient.Close() } + return nil } diff --git a/ethereum/listener.go b/ethereum/listener.go index 0999d3a..c60b709 100644 --- a/ethereum/listener.go +++ b/ethereum/listener.go @@ -8,13 +8,14 @@ import ( "os" "time" - "cosmossdk.io/log" ethereum "github.com/ethereum/go-ethereum" - ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/pascaldekloe/etherstream" + + "cosmossdk.io/log" + "github.com/strangelove-ventures/noble-cctp-relayer/relayer" "github.com/strangelove-ventures/noble-cctp-relayer/types" ) @@ -99,9 +100,7 @@ func (e *Ethereum) startMainStream( logger log.Logger, messageSent abi.Event, messageTransmitterAddress common.Address, - ) (stream <-chan ethtypes.Log, sub ethereum.Subscription, history []ethtypes.Log) { - var err error etherReader := etherstream.Reader{Backend: e.wsClient} @@ -142,7 +141,6 @@ func (e *Ethereum) getAndConsumeHistory( messageTransmitterAddress common.Address, messageTransmitterABI abi.ABI, start, end uint64) { - var toUnSub ethereum.Subscription var history []ethtypes.Log var err error @@ -203,7 +201,8 @@ func consumeHistory( messageSent abi.Event, messageTransmitterABI abi.ABI, ) { - for _, historicalLog := range history { + for i := range history { + historicalLog := history[i] parsedMsg, err := types.EvmLogToMessageState(messageTransmitterABI, messageSent, &historicalLog) if err != nil { logger.Error("Unable to parse history log into MessageState, skipping", "tx hash", historicalLog.TxHash.Hex(), "err", err) @@ -243,14 +242,15 @@ func (e *Ethereum) consumeStream( continue } logger.Info(fmt.Sprintf("New stream msg from %d with tx hash %s", parsedMsg.SourceDomain, parsedMsg.SourceTxHash)) - if txState == nil { + + switch { + case txState == nil: txState = &types.TxState{TxHash: parsedMsg.SourceTxHash, Msgs: []*types.MessageState{parsedMsg}} - } else if parsedMsg.SourceTxHash != txState.TxHash { + case parsedMsg.SourceTxHash != txState.TxHash: processingQueue <- txState txState = &types.TxState{TxHash: parsedMsg.SourceTxHash, Msgs: []*types.MessageState{parsedMsg}} - } else { + default: txState.Msgs = append(txState.Msgs, parsedMsg) - } default: if txState != nil { diff --git a/ethereum/listener_test.go b/ethereum/listener_test.go index 7d43c39..a6614e7 100644 --- a/ethereum/listener_test.go +++ b/ethereum/listener_test.go @@ -5,10 +5,11 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + "github.com/strangelove-ventures/noble-cctp-relayer/ethereum" testutil "github.com/strangelove-ventures/noble-cctp-relayer/test_util" "github.com/strangelove-ventures/noble-cctp-relayer/types" - "github.com/stretchr/testify/require" ) // TODO: update test. This test is currently outdated as the RPC endpoints likely won't have this much history @@ -34,16 +35,15 @@ func TestStartListener(t *testing.T) { tx := <-processingQueue expectedMsg := &types.MessageState{ - IrisLookupId: "a404f4155166a1fc7ffee145b5cac6d0f798333745289ab1db171344e226ef0c", + IrisLookupID: "a404f4155166a1fc7ffee145b5cac6d0f798333745289ab1db171344e226ef0c", Status: "created", SourceDomain: 0, DestDomain: 4, SourceTxHash: "0xe1d7729de300274ee3a2fd20ba179b14a8e3ffcd9d847c506b06760f0dad7802", } - require.Equal(t, expectedMsg.IrisLookupId, tx.Msgs[0].IrisLookupId) + require.Equal(t, expectedMsg.IrisLookupID, tx.Msgs[0].IrisLookupID) require.Equal(t, expectedMsg.Status, tx.Msgs[0].Status) require.Equal(t, expectedMsg.SourceDomain, tx.Msgs[0].SourceDomain) require.Equal(t, expectedMsg.DestDomain, tx.Msgs[0].DestDomain) require.Equal(t, expectedMsg.SourceTxHash, tx.Msgs[0].SourceTxHash) - } diff --git a/ethereum/util.go b/ethereum/util.go index ddb168c..11564da 100644 --- a/ethereum/util.go +++ b/ethereum/util.go @@ -4,12 +4,13 @@ import ( "crypto/ecdsa" "errors" "fmt" + "math/big" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rpc" - "math/big" ) -type JsonError interface { +type JSONError interface { Error() string ErrorCode() int ErrorData() interface{} diff --git a/ethereum/util_test.go b/ethereum/util_test.go index 7308d5d..64fb160 100644 --- a/ethereum/util_test.go +++ b/ethereum/util_test.go @@ -3,9 +3,10 @@ package ethereum_test import ( "testing" + "github.com/stretchr/testify/require" + "github.com/strangelove-ventures/noble-cctp-relayer/ethereum" testutil "github.com/strangelove-ventures/noble-cctp-relayer/test_util" - "github.com/stretchr/testify/require" ) func TestGetEthereumAccountNonce(t *testing.T) { @@ -13,7 +14,7 @@ func TestGetEthereumAccountNonce(t *testing.T) { ethConfig := a.Config.Chains["ethereum"].(*ethereum.ChainConfig) _, err := ethereum.GetEthereumAccountNonce(ethConfig.RPC, "0x4996f29b254c77972fff8f25e6f7797b3c9a0eb6") - require.Nil(t, err) + require.NoError(t, err) } // Return public ecdsa key and address given the private key @@ -24,5 +25,5 @@ func TestGetEcdsaKeyAddress(t *testing.T) { key, addr, err := ethereum.GetEcdsaKeyAddress(ethConfig.MinterPrivateKey) require.NotNil(t, key) require.NotNil(t, addr) - require.Nil(t, err) + require.NoError(t, err) } diff --git a/integration/ERC20.go b/integration/ERC20.go index 51412e3..49c2554 100644 --- a/integration/ERC20.go +++ b/integration/ERC20.go @@ -1,7 +1,7 @@ // Code generated - DO NOT EDIT. // This file is a generated binding and any manual changes will be lost. -package integration_testing +package integration_test import ( "errors" diff --git a/integration/config.go b/integration/config.go index 634a86d..9f36c8d 100644 --- a/integration/config.go +++ b/integration/config.go @@ -1,4 +1,4 @@ -package integration_testing +package integration_test import ( "os" @@ -26,11 +26,11 @@ type IntegrationConfig struct { } type IntegrationChain struct { - ChainId string `yaml:"chain-id"` + ChainID string `yaml:"chain-id"` Domain uint32 `yaml:"domain"` Address string `yaml:"address"` PrivateKey string `yaml:"private-key"` - Rpc string `yaml:"rpc"` + RPC string `yaml:"rpc"` UsdcTokenAddress string `yaml:"usdc-token-address"` TokenMessengerAddress string `yaml:"token-messenger-address"` DestinationCaller string `yaml:"destination-caller"` diff --git a/integration/deployed_relayer_test.go b/integration/deployed_relayer_test.go index 3fb7428..0999f66 100644 --- a/integration/deployed_relayer_test.go +++ b/integration/deployed_relayer_test.go @@ -1,16 +1,20 @@ -package integration_testing +package integration_test import ( "context" "encoding/hex" - "fmt" "math/big" "strconv" "testing" "time" - "cosmossdk.io/math" nobletypes "github.com/circlefin/noble-cctp/x/cctp/types" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/require" + sdkClient "github.com/cosmos/cosmos-sdk/client" clientTx "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" @@ -20,14 +24,12 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx/signing" xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" xauthtx "github.com/cosmos/cosmos-sdk/x/auth/tx" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethclient" + + "cosmossdk.io/math" + "github.com/strangelove-ventures/noble-cctp-relayer/cosmos" "github.com/strangelove-ventures/noble-cctp-relayer/ethereum" "github.com/strangelove-ventures/noble-cctp-relayer/ethereum/contracts" - "github.com/stretchr/testify/require" ) // The tests in this file are meant to test an actively deployed relayer. @@ -65,25 +67,25 @@ func TestNobleBurnToEthDeployed(t *testing.T) { var burnAmount = math.NewInt(1) - fmt.Printf("\nPath: %d -> %d\n", nobleCfg.Domain, ethConfig.Domain) + t.Logf("Path: %d -> %d", nobleCfg.Domain, ethConfig.Domain) - fmt.Println("Source Address: ", nobleCfg.Address) - cc, err := cosmos.NewProvider(nobleCfg.Rpc) + t.Logf("Source Address: %s", nobleCfg.Address) + cc, err := cosmos.NewProvider(nobleCfg.RPC) require.NoError(t, err) originalNobleBalance, err := getNobleAccountBalance(ctx, cc, nobleCfg.Address, uusdcDenom) require.NoError(t, err) - fmt.Println("Source Balance: ", originalNobleBalance) + t.Logf("Source Balance: %d", originalNobleBalance) - fmt.Println("Deposit Address: ", destAddress) + t.Logf("Deposit Address: %s", destAddress) // Get original usdc balance on Eth to verify that funds are deposited later - client, _ := ethclient.Dial(ethConfig.Rpc) + client, _ := ethclient.Dial(ethConfig.RPC) defer client.Close() ogBalance, err := getEthBalance(client, ethConfig.UsdcTokenAddress, destAddress) require.NoError(t, err) - fmt.Println("Destination Balance: ", ogBalance) + t.Logf("Destination Balance: %d", ogBalance) - fmt.Println("Burn Amount: ", burnAmount.String()) + t.Logf("Burn Amount: %s", burnAmount.String()) // set up sdk context interfaceRegistry := codectypes.NewInterfaceRegistry() @@ -98,7 +100,7 @@ func TestNobleBurnToEthDeployed(t *testing.T) { keyBz, _ := hex.DecodeString(nobleCfg.PrivateKey) privKey := secp256k1.PrivKey{Key: keyBz} nobleAddress, err := bech32.ConvertAndEncode("noble", privKey.PubKey().Address()) - require.Nil(t, err) + require.NoError(t, err) // destination address mintRecipient := make([]byte, 32) @@ -118,13 +120,13 @@ func TestNobleBurnToEthDeployed(t *testing.T) { ) err = txBuilder.SetMsgs(burnMsg) - require.Nil(t, err) + require.NoError(t, err) txBuilder.SetGasLimit(200000) // sign + broadcast txn accountNumber, accountSequence, err := getNobleAccountNumberSequenceGRPC(cc, nobleAddress) - require.Nil(t, err) + require.NoError(t, err) sigV2 := signing.SignatureV2{ PubKey: privKey.PubKey(), @@ -132,44 +134,47 @@ func TestNobleBurnToEthDeployed(t *testing.T) { SignMode: sdkContext.TxConfig.SignModeHandler().DefaultMode(), Signature: nil, }, - Sequence: uint64(accountSequence), + Sequence: accountSequence, } signerData := xauthsigning.SignerData{ - ChainID: nobleCfg.ChainId, - AccountNumber: uint64(accountNumber), - Sequence: uint64(accountSequence), + ChainID: nobleCfg.ChainID, + AccountNumber: accountNumber, + Sequence: accountSequence, } - txBuilder.SetSignatures(sigV2) + err = txBuilder.SetSignatures(sigV2) + require.NoError(t, err) + sigV2, err = clientTx.SignWithPrivKey( sdkContext.TxConfig.SignModeHandler().DefaultMode(), signerData, txBuilder, &privKey, sdkContext.TxConfig, - uint64(accountSequence), + accountSequence, ) - require.Nil(t, err) + require.NoError(t, err) err = txBuilder.SetSignatures(sigV2) - require.Nil(t, err) + require.NoError(t, err) // Generated Protobuf-encoded bytes. txBytes, err := sdkContext.TxConfig.TxEncoder()(txBuilder.GetTx()) - require.Nil(t, err) + require.NoError(t, err) rpcResponse, err := cc.RPCClient.BroadcastTxSync(context.Background(), txBytes) - require.Nil(t, err) - fmt.Printf("Deposit for Burn broadcasted: https://mintscan.io/noble-testnet/txs/%s\n", rpcResponse.Hash.String()) + require.NoError(t, err) + t.Logf("Deposit for Burn broadcasted: https://mintscan.io/noble-testnet/txs/%s", rpcResponse.Hash.String()) - fmt.Println("Waiting for circle to approve and destination wallet to receive funds...") + t.Log("Waiting for circle to approve and destination wallet to receive funds...") var newEthBalance uint64 for i := 0; i < 120; i++ { newEthBalance, err = getEthBalance(client, ethConfig.UsdcTokenAddress, destAddress) + require.NoError(t, err) if ogBalance+burnAmount.Uint64() == newEthBalance { - fmt.Println("Successfully minted into " + destAddress) + t.Log("Successfully minted into " + destAddress) break } time.Sleep(3 * time.Second) @@ -177,10 +182,10 @@ func TestNobleBurnToEthDeployed(t *testing.T) { newNobleBal, err := getNobleAccountBalance(ctx, cc, nobleCfg.Address, uusdcDenom) require.NoError(t, err) - fmt.Println("Source Balance: ", newNobleBal) + t.Log("Source Balance: ", newNobleBal) // verify eth balance - fmt.Println("Destination Balance: ", newEthBalance) + t.Logf("Destination Balance: %d", newEthBalance) require.Equal(t, ogBalance+burnAmount.Uint64(), newEthBalance) } @@ -188,7 +193,6 @@ func TestNobleBurnToEthDeployed(t *testing.T) { func TestEthBurnToNobleDeployed(t *testing.T) { c, err := ParseIntegration("../.ignore/integration.yaml") require.NoError(t, err) - ctx := context.Background() // -- NETWORK -- @@ -210,41 +214,41 @@ func TestEthBurnToNobleDeployed(t *testing.T) { destAddress := nobleCfg.Address - fmt.Printf("\nPath: %d -> %d\n", ethConfig.Domain, nobleCfg.Domain) + t.Logf("Path: %d -> %d", ethConfig.Domain, nobleCfg.Domain) - fmt.Println("Source Address: ", ethConfig.Address) + t.Logf("Source Address: %s", ethConfig.Address) - client, err := ethclient.Dial(ethConfig.Rpc) + client, err := ethclient.Dial(ethConfig.RPC) require.NoError(t, err) defer client.Close() originalEthBalance, err := getEthBalance(client, ethConfig.UsdcTokenAddress, ethConfig.Address) require.NoError(t, err) - fmt.Println("Source Balance: ", originalEthBalance) + t.Logf("Source Balance: %d", originalEthBalance) - fmt.Println("Destination Address: ", destAddress) + t.Logf("Destination Address: %s", destAddress) // Get original usdc balance on Noble to verify that funds are deposited later - cc, err := cosmos.NewProvider(nobleCfg.Rpc) + cc, err := cosmos.NewProvider(nobleCfg.RPC) require.NoError(t, err) originalNobleBalance, err := getNobleAccountBalance(ctx, cc, destAddress, uusdcDenom) require.NoError(t, err) - fmt.Println("Destination Balance: ", originalNobleBalance) + t.Logf("Destination Balance: %d", originalNobleBalance) - fmt.Println("Burn Amount: ", burnAmount.String()) + t.Logf("Burn Amount: %s", burnAmount.String()) privateKey, err := crypto.HexToECDSA(ethConfig.PrivateKey) - require.Nil(t, err) + require.NoError(t, err) - i, err := strconv.ParseInt(ethConfig.ChainId, 10, 64) + i, err := strconv.ParseInt(ethConfig.ChainID, 10, 64) require.NoError(t, err) ethChainID := big.NewInt(i) auth, err := bind.NewKeyedTransactorWithChainID(privateKey, ethChainID) - require.Nil(t, err) + require.NoError(t, err) // deal w/ nonce - nextNonce, err := ethereum.GetEthereumAccountNonce(ethConfig.Rpc, ethConfig.Address) + nextNonce, err := ethereum.GetEthereumAccountNonce(ethConfig.RPC, ethConfig.Address) require.NoError(t, err) auth.Nonce = big.NewInt(nextNonce) @@ -254,14 +258,14 @@ func TestEthBurnToNobleDeployed(t *testing.T) { // contractValue := burnAmount _, err = erc20.Approve(auth, common.HexToAddress(ethConfig.TokenMessengerAddress), burnAmount) - require.Nil(t, err) + require.NoError(t, err) // wait for erc20 approval to be on chain time.Sleep(10 * time.Second) // create tokenMessenger tokenMessenger, err := contracts.NewTokenMessenger(common.HexToAddress(ethConfig.TokenMessengerAddress), client) - require.Nil(t, err) + require.NoError(t, err) _, mintRecipientRaw, err := bech32.DecodeAndConvert(nobleCfg.Address) require.NoError(t, err) @@ -284,15 +288,15 @@ func TestEthBurnToNobleDeployed(t *testing.T) { require.NoError(t, err) time.Sleep(5 * time.Second) - fmt.Println("Deposit for Burn broadcasted. Tx Hash: ", tx.Hash().String()) + t.Logf("Deposit for Burn broadcasted. Tx Hash: %s", tx.Hash().String()) var newBalance uint64 - fmt.Println("Waiting for circle to approve and destination wallet to receive funds...") + t.Log("Waiting for circle to approve and destination wallet to receive funds...") for i := 0; i < 250; i++ { newBalance, err = getNobleAccountBalance(ctx, cc, destAddress, uusdcDenom) require.NoError(t, err) if originalNobleBalance+burnAmount.Uint64() == newBalance { - fmt.Println("Successfully minted at https://testnet.mintscan.io/noble-testnet/account/" + destAddress) + t.Logf("Successfully minted at https://testnet.mintscan.io/noble-testnet/account/" + destAddress) break } time.Sleep(3 * time.Second) @@ -300,9 +304,9 @@ func TestEthBurnToNobleDeployed(t *testing.T) { newEthBalance, err := getEthBalance(client, ethConfig.UsdcTokenAddress, ethConfig.Address) require.NoError(t, err) - fmt.Println("Source Balance: ", newEthBalance) + t.Logf("Source Balance: %d", newEthBalance) - fmt.Println("Destination Balance: ", newBalance) + t.Logf("Destination Balance: %d", newBalance) // verify noble balance require.Equal(t, originalNobleBalance+burnAmount.Uint64(), newBalance) } diff --git a/integration/eth_burn_to_noble_mint_test.go b/integration/eth_burn_to_noble_mint_test.go index f526db8..7157421 100644 --- a/integration/eth_burn_to_noble_mint_test.go +++ b/integration/eth_burn_to_noble_mint_test.go @@ -1,27 +1,28 @@ -package integration_testing +package integration_test import ( "context" "encoding/hex" - "fmt" "math/big" "testing" "time" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - "github.com/cosmos/cosmos-sdk/types/bech32" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + "github.com/cosmos/cosmos-sdk/types/bech32" + "github.com/strangelove-ventures/noble-cctp-relayer/cmd" "github.com/strangelove-ventures/noble-cctp-relayer/cosmos" "github.com/strangelove-ventures/noble-cctp-relayer/ethereum" "github.com/strangelove-ventures/noble-cctp-relayer/ethereum/contracts" "github.com/strangelove-ventures/noble-cctp-relayer/noble" "github.com/strangelove-ventures/noble-cctp-relayer/types" - "github.com/stretchr/testify/require" ) // TestEthBurnToNobleMint broadcasts a depositForBurn on Sepolia of 0.000001 USDC @@ -61,7 +62,7 @@ func TestEthBurnToNobleMint(t *testing.T) { var burnAmount = big.NewInt(1) - fmt.Println("Starting relayer...") + t.Log("Starting relayer...") registeredDomains := make(map[types.Domain]types.Chain) registeredDomains[0] = ethChain registeredDomains[4] = nobleChain @@ -77,26 +78,26 @@ func TestEthBurnToNobleMint(t *testing.T) { _, _, generatedWallet := testdata.KeyTestPubAddr() destAddress, _ := bech32.ConvertAndEncode("noble", generatedWallet) - fmt.Println("Noble destination address: ", destAddress) - fmt.Println("Minting on Noble to https://testnet.mintscan.io/noble-testnet/account/" + destAddress) + t.Logf("Noble destination address: %s", destAddress) + t.Logf("Minting on Noble to https://testnet.mintscan.io/noble-testnet/account/%s", destAddress) // verify noble usdc amount cc, err := cosmos.NewProvider(nobleCfg.RPC) - require.Nil(t, err) + require.NoError(t, err) originalNobleBalance, err := getNobleAccountBalance(ctx, cc, destAddress, uusdcDenom) require.NoError(t, err) // eth client client, err := ethclient.Dial(ethCfg.RPC) - require.Nil(t, err) + require.NoError(t, err) defer client.Close() privateKey, err := crypto.HexToECDSA(ethCfg.MinterPrivateKey) - require.Nil(t, err) + require.NoError(t, err) sepoliaChainID := big.NewInt(ethCfg.ChainID) auth, err := bind.NewKeyedTransactorWithChainID(privateKey, sepoliaChainID) - require.Nil(t, err) + require.NoError(t, err) // deal w/ nonce ethRelayerAddress, err := ethConvertPrivateKeytoAddress(ethCfg.MinterPrivateKey) @@ -110,17 +111,17 @@ func TestEthBurnToNobleMint(t *testing.T) { require.NoError(t, err) _, err = erc20.Approve(auth, common.HexToAddress(TokenMessengerAddressSepolia), burnAmount) - require.Nil(t, err) + require.NoError(t, err) // Ensure approval is on chain time.Sleep(20 * time.Second) // create tokenMessenger tokenMessenger, err := contracts.NewTokenMessenger(common.HexToAddress(TokenMessengerAddressSepolia), client) - require.Nil(t, err) + require.NoError(t, err) mintRecipientPadded := append([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, generatedWallet...) - require.Nil(t, err) + require.NoError(t, err) auth.Nonce = big.NewInt(nextNonce + 1) @@ -130,7 +131,7 @@ func TestEthBurnToNobleMint(t *testing.T) { require.NoError(t, err) privKey := secp256k1.PrivKey{Key: keyBz} caller, err := bech32.ConvertAndEncode("noble", privKey.PubKey().Address()) - require.Nil(t, err) + require.NoError(t, err) _, callerRaw, err := bech32.DecodeAndConvert(caller) require.NoError(t, err) destinationCallerPadded := append([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, callerRaw...) @@ -148,15 +149,15 @@ func TestEthBurnToNobleMint(t *testing.T) { } time.Sleep(5 * time.Second) - fmt.Printf("Transaction broadcasted: https://sepolia.etherscan.io/tx/%s\n", tx.Hash().String()) + t.Logf("Transaction broadcasted: https://sepolia.etherscan.io/tx/%s", tx.Hash().String()) var newBalance uint64 - fmt.Println("Waiting for circle to approve and destination wallet to receive funds.") + t.Log("Waiting for circle to approve and destination wallet to receive funds.") for i := 0; i < 250; i++ { newBalance, err = getNobleAccountBalance(ctx, cc, destAddress, uusdcDenom) require.NoError(t, err) if originalNobleBalance+burnAmount.Uint64() == newBalance { - fmt.Println("Successfully minted at https://testnet.mintscan.io/noble-testnet/account/" + destAddress) + t.Logf("Successfully minted at https://testnet.mintscan.io/noble-testnet/account/%s", destAddress) break } time.Sleep(2 * time.Second) diff --git a/integration/noble_burn_to_eth_mint_test.go b/integration/noble_burn_to_eth_mint_test.go index ddcef78..85bed0f 100644 --- a/integration/noble_burn_to_eth_mint_test.go +++ b/integration/noble_burn_to_eth_mint_test.go @@ -1,15 +1,18 @@ -package integration_testing +package integration_test import ( "context" "crypto/ecdsa" "encoding/hex" - "fmt" "testing" "time" - "cosmossdk.io/math" nobletypes "github.com/circlefin/noble-cctp/x/cctp/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/require" + sdkClient "github.com/cosmos/cosmos-sdk/client" clientTx "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" @@ -19,15 +22,14 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx/signing" xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" xauthtx "github.com/cosmos/cosmos-sdk/x/auth/tx" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethclient" + + "cosmossdk.io/math" + "github.com/strangelove-ventures/noble-cctp-relayer/cmd" "github.com/strangelove-ventures/noble-cctp-relayer/cosmos" "github.com/strangelove-ventures/noble-cctp-relayer/ethereum" "github.com/strangelove-ventures/noble-cctp-relayer/noble" "github.com/strangelove-ventures/noble-cctp-relayer/types" - "github.com/stretchr/testify/require" ) // TestNobleBurnToEthMint broadcasts a depositForBurn on Noble of 1 cent @@ -65,7 +67,7 @@ func TestNobleBurnToEthMint(t *testing.T) { err = ethChain.InitializeClients(ctx, a.Logger) require.NoError(t, err) - fmt.Println("Starting relayer...") + t.Log("Starting relayer...") registeredDomains := make(map[types.Domain]types.Chain) registeredDomains[0] = ethChain @@ -82,9 +84,9 @@ func TestNobleBurnToEthMint(t *testing.T) { ethDestinationAddress, _, err := generateEthWallet() require.NoError(t, err) - fmt.Println("Generated dest wallet: ", ethDestinationAddress) + t.Logf("Generated dest wallet: %s", ethDestinationAddress) - fmt.Println("Minting on Ethereum to https://sepolia.etherscan.io/address/" + ethDestinationAddress) + t.Logf("Minting on Ethereum to https://sepolia.etherscan.io/address/%s", ethDestinationAddress) // verify ethereum usdc amount client, _ := ethclient.Dial(ethCfg.RPC) @@ -108,7 +110,7 @@ func TestNobleBurnToEthMint(t *testing.T) { privKey := secp256k1.PrivKey{Key: keyBz} nobleAddress, err := bech32.ConvertAndEncode("noble", privKey.PubKey().Address()) - require.Nil(t, err) + require.NoError(t, err) mintRecipient := make([]byte, 32) copy(mintRecipient[12:], common.FromHex(ethDestinationAddress)) @@ -119,7 +121,7 @@ func TestNobleBurnToEthMint(t *testing.T) { callerPrivKey := ethCfg.MinterPrivateKey privateKeyBytes := common.FromHex(callerPrivKey) privateKey, err := crypto.ToECDSA(privateKeyBytes) - require.Nil(t, err) + require.NoError(t, err) pubKey := privateKey.Public() publicKeyECDSA, ok := pubKey.(*ecdsa.PublicKey) require.True(t, ok) @@ -138,17 +140,17 @@ func TestNobleBurnToEthMint(t *testing.T) { ) err = txBuilder.SetMsgs(burnMsg) - require.Nil(t, err) + require.NoError(t, err) txBuilder.SetGasLimit(nobleCfg.GasLimit) // sign + broadcast txn cc, err := cosmos.NewProvider(nobleCfg.RPC) - require.Nil(t, err) + require.NoError(t, err) accountNumber, accountSequence, err := getNobleAccountNumberSequenceGRPC(cc, nobleAddress) - require.Nil(t, err) + require.NoError(t, err) sigV2 := signing.SignatureV2{ PubKey: privKey.PubKey(), @@ -156,44 +158,46 @@ func TestNobleBurnToEthMint(t *testing.T) { SignMode: sdkContext.TxConfig.SignModeHandler().DefaultMode(), Signature: nil, }, - Sequence: uint64(accountSequence), + Sequence: accountSequence, } signerData := xauthsigning.SignerData{ ChainID: nobleCfg.ChainID, - AccountNumber: uint64(accountNumber), - Sequence: uint64(accountSequence), + AccountNumber: accountNumber, + Sequence: accountSequence, } - txBuilder.SetSignatures(sigV2) + err = txBuilder.SetSignatures(sigV2) + require.NoError(t, err) + sigV2, err = clientTx.SignWithPrivKey( sdkContext.TxConfig.SignModeHandler().DefaultMode(), signerData, txBuilder, &privKey, sdkContext.TxConfig, - uint64(accountSequence), + accountSequence, ) - require.Nil(t, err) + require.NoError(t, err) err = txBuilder.SetSignatures(sigV2) - require.Nil(t, err) + require.NoError(t, err) // Generated Protobuf-encoded bytes. txBytes, err := sdkContext.TxConfig.TxEncoder()(txBuilder.GetTx()) - require.Nil(t, err) + require.NoError(t, err) rpcResponse, err := cc.RPCClient.BroadcastTxSync(context.Background(), txBytes) - require.Nil(t, err) - fmt.Printf("Update pending: https://testnet.mintscan.io/noble-testnet/txs/%s\n", rpcResponse.Hash.String()) + require.NoError(t, err) + t.Logf("Update pending: https://testnet.mintscan.io/noble-testnet/txs/%s", rpcResponse.Hash.String()) - fmt.Println("Checking eth wallet...") + t.Log("Checking eth wallet...") var newBalance uint64 for i := 0; i < 60; i++ { newBalance, err = getEthBalance(client, usdcTokenAddressSepolia, ethDestinationAddress) require.NoError(t, err) if originalEthBalance+burnAmount.Uint64() == newBalance { - fmt.Println("Successfully minted at https://sepolia.etherscan.io/address/" + ethDestinationAddress) + t.Logf("Successfully minted at https://sepolia.etherscan.io/address/%s", ethDestinationAddress) break } time.Sleep(3 * time.Second) diff --git a/integration/types.go b/integration/types.go index 773a82b..82f72d7 100644 --- a/integration/types.go +++ b/integration/types.go @@ -1,4 +1,4 @@ -package integration_testing +package integration_test type BalanceResponse struct { Balance struct { @@ -21,11 +21,11 @@ type EthereumRPCPayload struct { Jsonrpc string `json:"jsonrpc"` Method string `json:"method"` Params []interface{} `json:"params"` - Id int `json:"id"` + ID int `json:"id"` } type EthereumTxCountResponse struct { - JsonRpc string `json:"jsonrpc"` - Id int `json:"id"` + JSONRPC string `json:"jsonrpc"` + ID int `json:"id"` Result string `json:"result"` } diff --git a/integration/util.go b/integration/util.go index e0b6602..ac0bdc5 100644 --- a/integration/util.go +++ b/integration/util.go @@ -1,33 +1,35 @@ -package integration_testing +package integration_test import ( "context" + "crypto/ecdsa" "encoding/hex" "fmt" "log" "math/big" "strings" - "crypto/ecdsa" - - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - bankTypes "github.com/cosmos/cosmos-sdk/x/bank/types" ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" + + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + bankTypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/strangelove-ventures/noble-cctp-relayer/cosmos" ) +//nolint:gosec const ( usdcTokenAddressSepolia = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" TokenMessengerAddressSepolia = "0x9f3B8679c73C2Fef8b59B4f3444d4e156fb70AA5" - - uusdcDenom = "uusdc" + uusdcDenom = "uusdc" ) +// nolint:unparam func getNobleAccountBalance(ctx context.Context, cc *cosmos.CosmosProvider, address, denom string) (uint64, error) { qc := bankTypes.NewQueryClient(cc) res, err := qc.Balance(ctx, &bankTypes.QueryBalanceRequest{ @@ -54,7 +56,6 @@ func getNobleAccountNumberSequenceGRPC(cc *cosmos.CosmosProvider, address string } return acc.GetAccountNumber(), acc.GetSequence(), nil - } func getEthBalance(client *ethclient.Client, usdcTokenAddress, walletAddress string) (uint64, error) { diff --git a/noble/broadcast.go b/noble/broadcast.go index defdb51..d1fb967 100644 --- a/noble/broadcast.go +++ b/noble/broadcast.go @@ -9,8 +9,8 @@ import ( "strconv" "time" - "cosmossdk.io/log" nobletypes "github.com/circlefin/noble-cctp/x/cctp/types" + sdkclient "github.com/cosmos/cosmos-sdk/client" clientTx "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" @@ -19,6 +19,9 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx/signing" xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" xauthtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + + "cosmossdk.io/log" + "github.com/strangelove-ventures/noble-cctp-relayer/relayer" "github.com/strangelove-ventures/noble-cctp-relayer/types" ) @@ -92,11 +95,9 @@ func (n *Noble) attemptBroadcast( sdkContext sdkclient.Context, txBuilder sdkclient.TxBuilder, ) error { - var receiveMsgs []sdk.Msg for _, msg := range msgs { - - used, err := n.cc.QueryUsedNonce(ctx, types.Domain(msg.SourceDomain), msg.Nonce) + used, err := n.cc.QueryUsedNonce(ctx, msg.SourceDomain, msg.Nonce) if err != nil { return fmt.Errorf("unable to query used nonce: %w", err) } @@ -153,39 +154,39 @@ func (n *Noble) attemptBroadcast( SignMode: sdkContext.TxConfig.SignModeHandler().DefaultMode(), Signature: nil, }, - Sequence: uint64(accountSequence), + Sequence: accountSequence, } signerData := xauthsigning.SignerData{ ChainID: n.chainID, - AccountNumber: uint64(n.accountNumber), - Sequence: uint64(accountSequence), + AccountNumber: n.accountNumber, + Sequence: accountSequence, } - txBuilder.SetSignatures(sigV2) + err := txBuilder.SetSignatures(sigV2) + if err != nil { + return fmt.Errorf("failed to set signatures: %w", err) + } - sigV2, err := clientTx.SignWithPrivKey( + sigV2, err = clientTx.SignWithPrivKey( sdkContext.TxConfig.SignModeHandler().DefaultMode(), signerData, txBuilder, n.privateKey, sdkContext.TxConfig, - uint64(accountSequence), + accountSequence, ) if err != nil { - return fmt.Errorf("failed to sign tx: %w", err) } if err := txBuilder.SetSignatures(sigV2); err != nil { - return fmt.Errorf("failed to set signatures: %w", err) } // Generated Protobuf-encoded bytes. txBytes, err := sdkContext.TxConfig.TxEncoder()(txBuilder.GetTx()) if err != nil { - return fmt.Errorf("failed to proto encode tx: %w", err) } diff --git a/noble/chain.go b/noble/chain.go index bfaa5cd..d4d7753 100644 --- a/noble/chain.go +++ b/noble/chain.go @@ -8,11 +8,13 @@ import ( "fmt" "sync" - "cosmossdk.io/log" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/bech32" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + "cosmossdk.io/log" + "github.com/strangelove-ventures/noble-cctp-relayer/cosmos" "github.com/strangelove-ventures/noble-cctp-relayer/types" ) @@ -162,8 +164,12 @@ func (n *Noble) InitializeClients(ctx context.Context, logger log.Logger) error return nil } -func (n *Noble) CloseClients() { +func (n *Noble) CloseClients() error { if n.cc != nil && n.cc.RPCClient.IsRunning() { - n.cc.RPCClient.Stop() + err := n.cc.RPCClient.Stop() + if err != nil { + return fmt.Errorf("error stopping noble rpc client: %w", err) + } } + return nil } diff --git a/noble/listener.go b/noble/listener.go index 50eddb9..516f913 100644 --- a/noble/listener.go +++ b/noble/listener.go @@ -6,6 +6,7 @@ import ( "time" "cosmossdk.io/log" + "github.com/strangelove-ventures/noble-cctp-relayer/relayer" "github.com/strangelove-ventures/noble-cctp-relayer/types" ) @@ -48,7 +49,7 @@ func (n *Noble) StartListener( blockQueue := make(chan uint64, n.blockQueueChannelSize) // history - currentBlock = currentBlock - lookback + currentBlock -= lookback for currentBlock <= chainTip { blockQueue <- currentBlock currentBlock++ @@ -125,7 +126,6 @@ func (n *Noble) flushMechanism( logger log.Logger, blockQueue chan uint64, ) { - logger.Debug(fmt.Sprintf("Flush mechanism started. Will flush every %v", flushInterval)) for { diff --git a/noble/listener_test.go b/noble/listener_test.go index 0d886b5..2d07ef0 100644 --- a/noble/listener_test.go +++ b/noble/listener_test.go @@ -5,10 +5,11 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + "github.com/strangelove-ventures/noble-cctp-relayer/noble" testutil "github.com/strangelove-ventures/noble-cctp-relayer/test_util" "github.com/strangelove-ventures/noble-cctp-relayer/types" - "github.com/stretchr/testify/require" ) // TODO: update test to not rely on live node with block history @@ -33,16 +34,15 @@ func TestStartListener(t *testing.T) { tx := <-processingQueue expectedMsg := &types.MessageState{ - IrisLookupId: "efe7cea3fd4785c3beab7f37876bdd48c5d4689c84d85a250813a2a7f01fe765", + IrisLookupID: "efe7cea3fd4785c3beab7f37876bdd48c5d4689c84d85a250813a2a7f01fe765", Status: "created", SourceDomain: 4, DestDomain: 0, SourceTxHash: "5002A249B1353FA59C1660EBAE5FA7FC652AC1E77F69CEF3A4533B0DF2864012", } - require.Equal(t, expectedMsg.IrisLookupId, tx.Msgs[0].IrisLookupId) + require.Equal(t, expectedMsg.IrisLookupID, tx.Msgs[0].IrisLookupID) require.Equal(t, expectedMsg.Status, tx.Msgs[0].Status) require.Equal(t, expectedMsg.SourceDomain, tx.Msgs[0].SourceDomain) require.Equal(t, expectedMsg.DestDomain, tx.Msgs[0].DestDomain) require.Equal(t, expectedMsg.SourceTxHash, tx.Msgs[0].SourceTxHash) - } diff --git a/noble/message_state.go b/noble/message_state.go index 6414b7e..20e6f4a 100644 --- a/noble/message_state.go +++ b/noble/message_state.go @@ -7,8 +7,10 @@ import ( "fmt" "time" - ctypes "github.com/cometbft/cometbft/rpc/core/types" "github.com/ethereum/go-ethereum/crypto" + + ctypes "github.com/cometbft/cometbft/rpc/core/types" + "github.com/strangelove-ventures/noble-cctp-relayer/types" ) @@ -22,7 +24,6 @@ func txToMessageState(tx *ctypes.ResultTx) ([]*types.MessageState, error) { for _, event := range tx.TxResult.Events { if event.Type == "circle.cctp.v1.MessageSent" { - //fmt.Printf("Saw cctp message %s - %d:%d\n", tx., i, j) var parsed bool var parseErrs error for _, attr := range event.Attributes { @@ -31,7 +32,6 @@ func txToMessageState(tx *ctypes.ResultTx) ([]*types.MessageState, error) { parseErrs = errors.Join(parseErrs, fmt.Errorf("failed to decode attribute key: %w", err)) } if string(decodedKey) == "message" { - // fmt.Printf("Saw message attribute %s - %d\n", tx.Hash, i) decodedValue, err := base64.StdEncoding.DecodeString(attr.Value) if err != nil { parseErrs = errors.Join(parseErrs, fmt.Errorf("error decoding attr.value: %w", err)) @@ -59,7 +59,7 @@ func txToMessageState(tx *ctypes.ResultTx) ([]*types.MessageState, error) { now := time.Now() messageState := &types.MessageState{ - IrisLookupId: hashedHexStr, + IrisLookupID: hashedHexStr, Status: types.Created, SourceDomain: types.Domain(msg.SourceDomain), DestDomain: types.Domain(msg.DestinationDomain), @@ -82,5 +82,4 @@ func txToMessageState(tx *ctypes.ResultTx) ([]*types.MessageState, error) { } return messageStates, nil - } diff --git a/relayer/metrics.go b/relayer/metrics.go index 7f1281f..f9ad56b 100644 --- a/relayer/metrics.go +++ b/relayer/metrics.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "net/http" + "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -47,7 +48,11 @@ func InitPromMetrics(port int16) *PromMetrics { // Expose /metrics HTTP endpoint go func() { http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg})) - log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil)) + server := &http.Server{ + Addr: fmt.Sprintf(":%d", port), + ReadTimeout: 3 * time.Second, + } + log.Fatal(server.ListenAndServe()) }() return m diff --git a/test_util/setup.go b/test_util/setup.go index 0e5d5c8..04079a3 100644 --- a/test_util/setup.go +++ b/test_util/setup.go @@ -1,29 +1,37 @@ package testutil import ( - "fmt" "os" "testing" "github.com/joho/godotenv" + "github.com/rs/zerolog" + "github.com/stretchr/testify/require" + + "cosmossdk.io/log" + "github.com/strangelove-ventures/noble-cctp-relayer/cmd" "github.com/strangelove-ventures/noble-cctp-relayer/ethereum" "github.com/strangelove-ventures/noble-cctp-relayer/noble" "github.com/strangelove-ventures/noble-cctp-relayer/types" - "github.com/stretchr/testify/require" ) +var logger log.Logger var EnvFile = os.ExpandEnv("$GOPATH/src/github.com/strangelove-ventures/noble-cctp-relayer/.env") func init() { + // define logger + logger = log.NewLogger(os.Stdout, log.LevelOption(zerolog.ErrorLevel)) + err := godotenv.Load(EnvFile) if err != nil { - fmt.Println(fmt.Errorf("error loading env file")) + logger.Error("error loading env file", "err", err) os.Exit(1) } } func ConfigSetup(t *testing.T) (a *cmd.AppState, registeredDomains map[types.Domain]types.Chain) { + t.Helper() var testConfig = types.Config{ Chains: map[string]types.ChainConfig{ @@ -40,7 +48,7 @@ func ConfigSetup(t *testing.T) (a *cmd.AppState, registeredDomains map[types.Dom }, }, Circle: types.CircleSettings{ - AttestationBaseUrl: "https://iris-api-sandbox.circle.com/attestations/", + AttestationBaseURL: "https://iris-api-sandbox.circle.com/attestations/", FetchRetries: 0, FetchRetryInterval: 3, }, @@ -65,5 +73,4 @@ func ConfigSetup(t *testing.T) (a *cmd.AppState, registeredDomains map[types.Dom } return a, registeredDomains - } diff --git a/types/chain.go b/types/chain.go index 30851d4..d68c998 100644 --- a/types/chain.go +++ b/types/chain.go @@ -5,6 +5,7 @@ import ( "time" "cosmossdk.io/log" + "github.com/strangelove-ventures/noble-cctp-relayer/relayer" ) @@ -38,7 +39,7 @@ type Chain interface { ) error // CloseClients is a cleanup function to close any open clients - CloseClients() + CloseClients() error // InitializeBroadcaster initializes the minter account info for the chain. InitializeBroadcaster( diff --git a/types/config.go b/types/config.go index dd6efd6..65af0fc 100644 --- a/types/config.go +++ b/types/config.go @@ -6,7 +6,7 @@ type Config struct { Circle CircleSettings `yaml:"circle"` ProcessorWorkerCount uint32 `yaml:"processor-worker-count"` - Api struct { + API struct { TrustedProxies []string `yaml:"trusted-proxies"` } `yaml:"api"` } @@ -17,13 +17,13 @@ type ConfigWrapper struct { Circle CircleSettings `yaml:"circle"` ProcessorWorkerCount uint32 `yaml:"processor-worker-count"` - Api struct { + API struct { TrustedProxies []string `yaml:"trusted-proxies"` } `yaml:"api"` } type CircleSettings struct { - AttestationBaseUrl string `yaml:"attestation-base-url"` + AttestationBaseURL string `yaml:"attestation-base-url"` FetchRetries int `yaml:"fetch-retries"` FetchRetryInterval int `yaml:"fetch-retry-interval"` } diff --git a/types/message_state.go b/types/message_state.go index 55fbd76..d25328c 100644 --- a/types/message_state.go +++ b/types/message_state.go @@ -33,7 +33,7 @@ type TxState struct { } type MessageState struct { - IrisLookupId string // hex encoded MessageSent bytes + IrisLookupID string // hex encoded MessageSent bytes Status string // created, pending, attested, complete, failed, filtered Attestation string // hex encoded attestation SourceDomain Domain // uint32 source domain id @@ -63,7 +63,7 @@ func EvmLogToMessageState(abi abi.ABI, messageSent abi.Event, log *ethtypes.Log) hashedHexStr := hex.EncodeToString(hashed) messageState = &MessageState{ - IrisLookupId: hashedHexStr, + IrisLookupID: hashedHexStr, Status: Created, SourceDomain: Domain(message.SourceDomain), DestDomain: Domain(message.DestinationDomain), @@ -85,7 +85,7 @@ func EvmLogToMessageState(abi abi.ABI, messageSent abi.Event, log *ethtypes.Log) // Equal checks if two MessageState instances are equal func (m *MessageState) Equal(other *MessageState) bool { - return (m.IrisLookupId == other.IrisLookupId && + return (m.IrisLookupID == other.IrisLookupID && m.Status == other.Status && m.Attestation == other.Attestation && m.SourceDomain == other.SourceDomain && diff --git a/types/message_state_test.go b/types/message_state_test.go index 1b83764..9752ddd 100644 --- a/types/message_state_test.go +++ b/types/message_state_test.go @@ -2,7 +2,6 @@ package types_test import ( "context" - "fmt" "math/big" "os" "testing" @@ -13,10 +12,11 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/joho/godotenv" "github.com/pascaldekloe/etherstream" - testutil "github.com/strangelove-ventures/noble-cctp-relayer/test_util" - "github.com/strangelove-ventures/noble-cctp-relayer/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + testutil "github.com/strangelove-ventures/noble-cctp-relayer/test_util" + "github.com/strangelove-ventures/noble-cctp-relayer/types" ) // TODO: update so it doesn't rely on block history @@ -25,15 +25,15 @@ func TestToMessageStateSuccess(t *testing.T) { require.NoError(t, err) messageTransmitter, err := os.Open("../cmd/ethereum/abi/MessageTransmitter.json") - require.Nil(t, err) + require.NoError(t, err) messageTransmitterABI, err := abi.JSON(messageTransmitter) - require.Nil(t, err) + require.NoError(t, err) messageSent := messageTransmitterABI.Events["MessageSent"] ethClient, err := ethclient.DialContext(context.Background(), os.Getenv("SEPOLIA_RPC")) - require.Nil(t, err) + require.NoError(t, err) messageTransmitterAddress := common.HexToAddress("0x26413e8157CD32011E726065a5462e97dD4d03D9") @@ -47,7 +47,7 @@ func TestToMessageStateSuccess(t *testing.T) { etherReader := etherstream.Reader{Backend: ethClient} _, _, history, err := etherReader.QueryWithHistory(context.Background(), &query) - require.Nil(t, err) + require.NoError(t, err) messageState, err := types.EvmLogToMessageState(messageTransmitterABI, messageSent, &history[0]) @@ -57,7 +57,7 @@ func TestToMessageStateSuccess(t *testing.T) { rawMessageSentBytes := event["message"].([]byte) destCaller := make([]byte, 32) - assert.Equal(t, "e40ed0e983675678715972bd50d6abc417735051b0255f3c0916911957eda603", messageState.IrisLookupId) + assert.Equal(t, "e40ed0e983675678715972bd50d6abc417735051b0255f3c0916911957eda603", messageState.IrisLookupID) assert.Equal(t, "created", messageState.Status) assert.Equal(t, "", messageState.Attestation) assert.Equal(t, uint32(0), messageState.SourceDomain) @@ -67,6 +67,6 @@ func TestToMessageStateSuccess(t *testing.T) { assert.Equal(t, rawMessageSentBytes, messageState.MsgSentBytes) assert.Equal(t, destCaller, messageState.DestinationCaller) assert.Equal(t, "", messageState.Channel) - fmt.Println(messageState) - require.Nil(t, err) + t.Log(messageState) + require.NoError(t, err) } diff --git a/types/state_test.go b/types/state_test.go index c8b0f54..be5e060 100644 --- a/types/state_test.go +++ b/types/state_test.go @@ -12,7 +12,7 @@ func TestStateHandling(t *testing.T) { txHash := "123456789" msg := MessageState{ SourceTxHash: txHash, - IrisLookupId: "123", + IrisLookupID: "123", Status: Filtered, MsgSentBytes: []byte("i like turtles"), } @@ -37,7 +37,7 @@ func TestStateHandling(t *testing.T) { // even though loadedMsg is a pointer, if we add to the array, we need to re-store in cache. msg2 := MessageState{ SourceTxHash: txHash, - IrisLookupId: "123", + IrisLookupID: "123", Status: Filtered, MsgSentBytes: []byte("mock bytes 2"), } @@ -46,5 +46,5 @@ func TestStateHandling(t *testing.T) { stateMap.Store(txHash, loadedMsg) loadedMsg3, _ := stateMap.Load(txHash) - require.Equal(t, 2, len(loadedMsg3.Msgs)) + require.Len(t, loadedMsg3.Msgs, 2) }