Skip to content
193 changes: 193 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
# .golangci.yml
version: "2"

run:
timeout: 5m
tests: true
# Keep it simple: lint the whole module.
# If you need to exclude generated dirs, do it in exclusions.paths.

linters:
default: none
enable:
# correctness / bugs
- errcheck
- errorlint
- govet
- ineffassign
- staticcheck
- unused
- bodyclose
- copyloopvar
- intrange
- unconvert
- unparam
- noctx

# security
- gosec

# maintainability / readability
- revive
- gocritic
- gocyclo
- funlen
- dupl
- goconst
- misspell
- whitespace
- nolintlint
- godox
- lll
- dogsled
- nakedret
- testifylint

# numbers / magic constants (often noisy; keep, but tuned below)
- mnd

settings:
dupl:
threshold: 100

funlen:
# Lines are a poor signal; statements are a decent one.
lines: -1
statements: 50

goconst:
min-len: 3
min-occurrences: 3

gocritic:
enabled-tags:
- diagnostic
- performance
- style
# "opinionated" and "experimental" tend to create churn in most repos.
disabled-tags:
- opinionated
- experimental
disabled-checks:
- dupImport
- ifElseChain
- octalLiteral
- whyNoLint

gocyclo:
min-complexity: 15

godox:
keywords:
- TODO
- FIXME

mnd:
checks:
- argument
- case
- condition
- return
ignored-numbers:
- "0"
- "1"
- "2"
- "3"
ignored-functions:
- strings.SplitN
- time.Duration
- time.Sleep

govet:
enable:
- nilness
- shadow
# Keep govet defaults + these; avoid repo-specific printf funcs unless needed.

errorlint:
asserts: false

lll:
line-length: 140
tab-width: 1

misspell:
locale: US

nolintlint:
allow-unused: false
require-explanation: true
require-specific: true

revive:
# A small, stable ruleset. Add more only when you actually want them enforced.
rules:
- name: indent-error-flow
- name: empty-lines
- name: unused-parameter
- name: unused-receiver
- name: early-return
- name: var-naming
- name: exported
disabled: true # too chatty unless your repo is strict about comments

exclusions:
presets:
- comments
- std-error-handling
- common-false-positives
- legacy

# NOTE: exclusions.paths are REGEX (not globs, not plain paths).
# Anchor them so you only exclude those directories.
paths:
- ^pkg/apidb
- ^pkg/auth
- ^pkg/canton
- ^pkg/config
- ^pkg/db
- ^pkg/ethereum
- ^pkg/ethrpc
- ^pkg/keys
- ^pkg/registration
- ^pkg/relayer
- ^pkg/service
- ^cmd
- ^internal

rules:
- path: (.+)_test\.go$
linters: [dupl, funlen, gocyclo, mnd, lll]

- path: \.gen\.go$
linters: [revive, gocritic, goconst, gocyclo, funlen, lll, dupl, mnd]

formatters:
enable:
- gofmt
- goimports
settings:
gofmt:
rewrite-rules:
- pattern: "interface{}"
replacement: "any"
goimports:
local-prefixes:
- github.com/chainsafe/canton-middleware

exclusions:
# NOTE: these are REGEX patterns (not globs)
paths:
- ^pkg/apidb
- ^pkg/auth
- ^pkg/canton
- ^pkg/config
- ^pkg/db
- ^pkg/ethereum
- ^pkg/ethrpc
- ^pkg/keys
- ^pkg/registration
- ^pkg/relayer
- ^pkg/service
- ^cmd
- ^internal
9 changes: 7 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,14 @@ deps:
go mod download
go mod tidy

get_lint:
if [ ! -f ./bin/golangci-lint ]; then \
curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v2.9.0; \
fi;
Comment on lines +31 to +33
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The version v2.9.0 for golangci-lint is invalid and will cause the get_lint target to fail. The latest version of golangci-lint is v1.59.1. Please use a valid version. Also, the install script is invoked in a way that might not place the binary in ./bin. It's better to explicitly use the -b flag to specify the output directory.

	if [ ! -f ./bin/golangci-lint ]; then \
		curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ./bin v1.59.1; \
	fi;


# Run linter
lint:
golangci-lint run
lint: get_lint
./bin/golangci-lint run

# Format code
fmt:
Expand Down
10 changes: 5 additions & 5 deletions cmd/api-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"time"

"github.com/chainsafe/canton-middleware/pkg/apidb"
"github.com/chainsafe/canton-middleware/pkg/canton"
canton "github.com/chainsafe/canton-middleware/pkg/canton-sdk/client"
"github.com/chainsafe/canton-middleware/pkg/config"
"github.com/chainsafe/canton-middleware/pkg/ethrpc"
"github.com/chainsafe/canton-middleware/pkg/keys"
Expand Down Expand Up @@ -58,7 +58,7 @@ func main() {
zap.String("database", cfg.Database.Database))

// Create Canton client
cantonClient, err := canton.NewClient(&cfg.Canton, logger)
cantonClient, err := canton.NewFromAppConfig(context.Background(), &cfg.Canton, canton.WithLogger(logger))
if err != nil {
logger.Fatal("Failed to create Canton client", zap.Error(err))
}
Expand All @@ -67,7 +67,7 @@ func main() {
zap.String("rpc_url", cfg.Canton.RPCURL))

// Create and start reconciler for balance cache
reconciler := apidb.NewReconciler(db, cantonClient, logger)
reconciler := apidb.NewReconciler(db, cantonClient.Token, logger)

// Run initial reconciliation on startup
logger.Info("Running initial balance reconciliation...",
Expand All @@ -86,7 +86,7 @@ func main() {
defer reconciler.Stop()

// Create shared token service
tokenService := service.NewTokenService(cfg, db, cantonClient, logger)
tokenService := service.NewTokenService(cfg, db, cantonClient.Token, logger)

// Create key store for custodial Canton key management
masterKeyStr := os.Getenv(cfg.KeyManagement.MasterKeyEnv)
Expand Down Expand Up @@ -115,7 +115,7 @@ func main() {
}))

// Create registration handler with key store
registrationHandler := registration.NewHandler(cfg, db, cantonClient, keyStore, logger)
registrationHandler := registration.NewHandler(cfg, db, cantonClient.Identity, keyStore, logger)
mux.Handle("/register", registrationHandler)
logger.Info("Registration endpoint enabled at /register")

Expand Down
6 changes: 3 additions & 3 deletions cmd/relayer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"time"

"github.com/chainsafe/canton-middleware/pkg/apidb"
"github.com/chainsafe/canton-middleware/pkg/canton"
canton "github.com/chainsafe/canton-middleware/pkg/canton-sdk/client"
"github.com/chainsafe/canton-middleware/pkg/config"
"github.com/chainsafe/canton-middleware/pkg/db"
"github.com/chainsafe/canton-middleware/pkg/ethereum"
Expand Down Expand Up @@ -56,7 +56,7 @@ func main() {
logger.Info("Database connection established")

// Initialize Canton client
cantonClient, err := canton.NewClient(&cfg.Canton, logger)
cantonClient, err := canton.NewFromAppConfig(context.Background(), &cfg.Canton, canton.WithLogger(logger))
if err != nil {
logger.Fatal("Failed to initialize Canton client", zap.Error(err))
}
Expand Down Expand Up @@ -85,7 +85,7 @@ func main() {

// Start relayer engine first so we can reference it in HTTP handlers
ctx := context.Background()
engine := relayer.NewEngine(cfg, cantonClient, ethClient, store, logger)
engine := relayer.NewEngine(cfg, cantonClient.Bridge, ethClient, store, logger)
if apiStore != nil {
engine.SetAPIDB(apiStore)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/apidb/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"fmt"
"time"

"github.com/chainsafe/canton-middleware/pkg/canton"
canton "github.com/chainsafe/canton-middleware/pkg/canton-sdk/token"
)

// BridgeEvent represents a stored bridge event for reconciliation
Expand Down
10 changes: 5 additions & 5 deletions pkg/apidb/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ import (
"sync"
"time"

"github.com/chainsafe/canton-middleware/pkg/canton"
canton "github.com/chainsafe/canton-middleware/pkg/canton-sdk/token"
"github.com/shopspring/decimal"
"go.uber.org/zap"
)

// Reconciler handles synchronization between Canton ledger state and DB cache
type Reconciler struct {
db *Store
cantonClient *canton.Client
cantonClient canton.Token
logger *zap.Logger

stopCh chan struct{}
wg sync.WaitGroup
}

// NewReconciler creates a new reconciler
func NewReconciler(db *Store, cantonClient *canton.Client, logger *zap.Logger) *Reconciler {
func NewReconciler(db *Store, cantonClient canton.Token, logger *zap.Logger) *Reconciler {
return &Reconciler{
db: db,
cantonClient: cantonClient,
Expand All @@ -43,7 +43,7 @@ func (r *Reconciler) ReconcileAll(ctx context.Context) error {
start := time.Now()

// Get all holdings from Canton to calculate total supply
holdings, err := r.cantonClient.GetAllCIP56Holdings(ctx)
holdings, err := r.cantonClient.GetAllHoldings(ctx)
if err != nil {
return fmt.Errorf("failed to get holdings from Canton: %w", err)
}
Expand Down Expand Up @@ -136,7 +136,7 @@ func (r *Reconciler) ReconcileUserBalancesFromHoldings(ctx context.Context) erro
start := time.Now()

// Get all holdings from Canton
holdings, err := r.cantonClient.GetAllCIP56Holdings(ctx)
holdings, err := r.cantonClient.GetAllHoldings(ctx)
if err != nil {
return fmt.Errorf("failed to get holdings from Canton: %w", err)
}
Expand Down
Loading