Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ require (
github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20250827130336-5922343458be
github.com/smartcontractkit/chainlink-framework/capabilities v0.0.0-20250818175541-3389ac08a563
github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250717121125-2350c82883e2
github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20250717121125-2350c82883e2
github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20251020150604-8ab84f7bad1a
github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250729142306-508e798f6a5d
github.com/smartcontractkit/chainlink-protos/svr v1.1.0
github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250815105909-75499abc4335
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -630,8 +630,8 @@ github.com/smartcontractkit/chainlink-framework/capabilities v0.0.0-202508181755
github.com/smartcontractkit/chainlink-framework/capabilities v0.0.0-20250818175541-3389ac08a563/go.mod h1:jP5mrOLFEYZZkl7EiCHRRIMSSHCQsYypm1OZSus//iI=
github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250717121125-2350c82883e2 h1:JU1JUrkzdAUHsOYdS9DENPkJfmrxweFRPRSztad6oPM=
github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250717121125-2350c82883e2/go.mod h1:+pRGfDej1r7cHMs1dYmuyPuOZzYB9Q+PKu0FvZOYlmw=
github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20250717121125-2350c82883e2 h1:ysZjKH+BpWlQhF93kr/Lc668UlCvT9NjfcsGdZT19I8=
github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20250717121125-2350c82883e2/go.mod h1:jo+cUqNcHwN8IF7SInQNXDZ8qzBsyMpnLdYbDswviFc=
github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20251020150604-8ab84f7bad1a h1:pr0VFI7AWlDVJBEkcvzXWd97V8w8QMNjRdfPVa/IQLk=
github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20251020150604-8ab84f7bad1a/go.mod h1:jo+cUqNcHwN8IF7SInQNXDZ8qzBsyMpnLdYbDswviFc=
github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250729142306-508e798f6a5d h1:pTYIcsWHTMG5fAcbRUA8Qk5yscXKdSpopQ0DUEOjPik=
github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250729142306-508e798f6a5d/go.mod h1:2JTBNp3FlRdO/nHc4dsc9bfxxMClMO1Qt8sLJgtreBY=
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250911124514-5874cc6d62b2 h1:1/KdO5AbUr3CmpLjMPuJXPo2wHMbfB8mldKLsg7D4M8=
Expand Down
5 changes: 4 additions & 1 deletion pkg/chains/legacyevm/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,10 @@ func newChain(cfg *config.ChainScoped, nodes []*toml.Node, opts ChainRelayOpts,

var balanceMonitor monitor.BalanceMonitor
if opts.ChainConfigs.RPCEnabled() && cfg.EVM().BalanceMonitor().Enabled() {
balanceMonitor = monitor.NewBalanceMonitor(cl, opts.KeyStore, l)
balanceMonitor, err = monitor.NewBalanceMonitor(cl, opts.KeyStore, l)
if err != nil {
return nil, fmt.Errorf("failed to create balance monitor for chain with ID %s: %w", chainID, err)
}
headBroadcaster.Subscribe(balanceMonitor)
}

Expand Down
29 changes: 18 additions & 11 deletions pkg/monitor/balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type (

ethClient evmclient.Client
chainIDStr string
balanceMetrics metrics.GenericBalanceMetrics
ethKeyStore keys.AddressLister
ethBalances map[common.Address]*assets.Eth
ethBalancesMtx sync.RWMutex
Expand All @@ -51,20 +52,26 @@ type (
var _ BalanceMonitor = (*balanceMonitor)(nil)

// NewBalanceMonitor returns a new balanceMonitor
func NewBalanceMonitor(ethClient evmclient.Client, ethKeyStore keys.AddressLister, lggr logger.Logger) *balanceMonitor {
func NewBalanceMonitor(ethClient evmclient.Client, ethKeyStore keys.AddressLister, lggr logger.Logger) (*balanceMonitor, error) {
balanceMetrics, err := metrics.NewGenericBalanceMetrics(metrics.EVM, ethClient.ConfiguredChainID().String())
if err != nil {
return nil, fmt.Errorf("failed to create balance metrics: %w", err)
}

bm := &balanceMonitor{
ethClient: ethClient,
chainIDStr: ethClient.ConfiguredChainID().String(),
ethKeyStore: ethKeyStore,
ethBalances: make(map[common.Address]*assets.Eth),
ethClient: ethClient,
chainIDStr: ethClient.ConfiguredChainID().String(),
balanceMetrics: balanceMetrics,
ethKeyStore: ethKeyStore,
ethBalances: make(map[common.Address]*assets.Eth),
}
bm.Service, bm.eng = services.Config{
Name: "BalanceMonitor",
Start: bm.start,
Close: bm.close,
}.NewServiceEngine(lggr)
bm.sleeperTask = utils.NewSleeperTaskCtx(&worker{bm: bm})
return bm
return bm, nil
}

func (bm *balanceMonitor) start(ctx context.Context) error {
Expand All @@ -87,8 +94,8 @@ func (bm *balanceMonitor) OnNewLongestChain(_ context.Context, _ *evmtypes.Head)
}
}

func (bm *balanceMonitor) updateBalance(ethBal assets.Eth, address common.Address) {
bm.promUpdateEthBalance(&ethBal, address)
func (bm *balanceMonitor) updateBalance(ctx context.Context, ethBal assets.Eth, address common.Address) {
bm.updateBalanceMetrics(ctx, &ethBal, address)

bm.ethBalancesMtx.Lock()
oldBal := bm.ethBalances[address]
Expand Down Expand Up @@ -126,15 +133,15 @@ var promETHBalance = promauto.NewGaugeVec(
[]string{"account", "evmChainID"},
)

func (bm *balanceMonitor) promUpdateEthBalance(balance *assets.Eth, from common.Address) {
func (bm *balanceMonitor) updateBalanceMetrics(ctx context.Context, balance *assets.Eth, from common.Address) {
balanceFloat, err := ApproximateFloat64(balance)

if err != nil {
bm.eng.Error(fmt.Errorf("updatePrometheusEthBalance: %w", err))
return
}

metrics.NodeBalance.WithLabelValues(from.Hex(), bm.chainIDStr, metrics.EVM).Set(balanceFloat)
bm.balanceMetrics.RecordNodeBalance(ctx, from.Hex(), balanceFloat)
// TODO: Remove deprecated metric
promETHBalance.WithLabelValues(from.Hex(), bm.chainIDStr).Set(balanceFloat)
}
Expand Down Expand Up @@ -179,7 +186,7 @@ func (w *worker) checkAccountBalance(ctx context.Context, address common.Address
)
} else {
ethBal := assets.Eth(*bal)
w.bm.updateBalance(ethBal, address)
w.bm.updateBalance(ctx, ethBal, address)
}
}

Expand Down
18 changes: 12 additions & 6 deletions pkg/monitor/balance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ func TestBalanceMonitor_Start(t *testing.T) {
ethKeyStore := keystest.Addresses{k0Addr, k1Addr}
ethClient := newEthClientMock(t)

bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t))
bm, err := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t))
require.NoError(t, err)

k0bal := big.NewInt(42)
k1bal := big.NewInt(43)
Expand All @@ -64,7 +65,8 @@ func TestBalanceMonitor_Start(t *testing.T) {
ethKeyStore := keystest.Addresses{k0Addr}
ethClient := newEthClientMock(t)

bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t))
bm, err := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t))
require.NoError(t, err)
k0bal := big.NewInt(42)

ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt).Once().Return(k0bal, nil)
Expand All @@ -81,7 +83,8 @@ func TestBalanceMonitor_Start(t *testing.T) {
ethKeyStore := keystest.Addresses{k0Addr}
ethClient := newEthClientMock(t)

bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t))
bm, err := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t))
require.NoError(t, err)
ctxCancelledAwaiter := testutils.NewAwaiter()

ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt).Once().Run(func(args mock.Arguments) {
Expand All @@ -108,7 +111,8 @@ func TestBalanceMonitor_Start(t *testing.T) {
ethKeyStore := keystest.Addresses{k0Addr}
ethClient := newEthClientMock(t)

bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t))
bm, err := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t))
require.NoError(t, err)

ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt).
Once().
Expand All @@ -131,7 +135,8 @@ func TestBalanceMonitor_OnNewLongestChain_UpdatesBalance(t *testing.T) {
ethKeyStore := keystest.Addresses{k0Addr, k1Addr}
ethClient := newEthClientMock(t)

bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t))
bm, err := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t))
require.NoError(t, err)
k0bal := big.NewInt(42)
// Deliberately larger than a 64 bit unsigned integer to test overflow
k1bal := big.NewInt(0)
Expand Down Expand Up @@ -177,7 +182,8 @@ func TestBalanceMonitor_FewerRPCCallsWhenBehind(t *testing.T) {
ethKeyStore := keystest.Addresses{testutils.NewAddress()}
ethClient := newEthClientMock(t)

bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t))
bm, err := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t))
require.NoError(t, err)
ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).
Once().
Return(big.NewInt(1), nil)
Expand Down
Loading