Skip to content

Commit

Permalink
feat(monitor): add support for monitoring additional contracts (#2493)
Browse files Browse the repository at this point in the history
contracts.ToFund didn't quite work well for monitoring contracts we want
to withdraw from instead of adding funding to, so I added
contracts.ToWithdraw and incorporated it into the monitor. Initially
prepared it for the gas pumps.

issue: none
  • Loading branch information
Zodomo authored Nov 19, 2024
1 parent a9457cf commit 6d4c649
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 75 deletions.
4 changes: 2 additions & 2 deletions e2e/app/fund.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@ func FundAccounts(ctx context.Context, def Definition, hotOnly bool, dryRun bool
if err := fund(ctrCtx, fundParams{
backend: backend,
account: contract.Address,
minBalance: contract.Thresholds.MinBalance(),
targetBalance: contract.Thresholds.TargetBalance(),
minBalance: contract.FundThresholds.MinBalance(),
targetBalance: contract.FundThresholds.TargetBalance(),
saneMax: saneMax(chain.NativeToken),
dryRun: dryRun,
funder: funderAddr,
Expand Down
124 changes: 124 additions & 0 deletions lib/contracts/contracts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package contracts

import (
"context"
"math/big"

"github.com/omni-network/omni/halo/genutil/evm/predeploys"
"github.com/omni-network/omni/lib/netconf"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params"

"cosmossdk.io/math"
)

// Contract defines a contract to monitor.
type Contract struct {
Name string
Address common.Address
OnlyOmniEVM bool
NotOmniEVM bool
FundThresholds *FundThresholds
WithdrawThresholds *WithdrawThresholds
}

// ToMonitor returns all contracts for the given network relevant to the monitor.
func ToMonitor(ctx context.Context, network netconf.ID) ([]Contract, error) {
addrs, err := GetAddresses(ctx, network)
if err != nil {
return nil, err
}

return []Contract{
// Funded contracts
{
Name: "gas-station",
Address: addrs.GasStation,
OnlyOmniEVM: true,
NotOmniEVM: false,
FundThresholds: &FundThresholds{minEther: 200, targetEther: 1000}, // GasStation funds user GasPump requests, and needs a large OMNI balance.
},
// Withdrawal contracts
{
Name: "gas-pump",
Address: addrs.GasPump,
OnlyOmniEVM: false,
NotOmniEVM: true,
WithdrawThresholds: &WithdrawThresholds{maxEther: 10},
},
// Monitoring contracts
{
Name: "staking",
Address: common.HexToAddress(predeploys.Staking),
OnlyOmniEVM: true,
NotOmniEVM: false,
},
{
Name: "nativeBridge",
Address: common.HexToAddress(predeploys.OmniBridgeNative),
OnlyOmniEVM: true,
NotOmniEVM: false,
},
}, nil
}

// ToFund returns all fundable contracts for the given network.
func ToFund(ctx context.Context, network netconf.ID) ([]Contract, error) {
contracts, err := ToMonitor(ctx, network)
if err != nil {
return nil, err
}

var fundContracts []Contract
for _, contract := range contracts {
if contract.FundThresholds != nil {
fundContracts = append(fundContracts, contract)
}
}

return fundContracts, nil
}

// FundThresholds defines the thresholds for funding a contract.
type FundThresholds struct {
minEther float64
targetEther float64
}

// MinBalance returns the minimum balance required for funding a contract.
func (t FundThresholds) MinBalance() *big.Int {
gwei := t.minEther * params.GWei

if gwei < 1 {
panic("ether float64 must be greater than 1 Gwei")
}

return math.NewInt(params.GWei).MulRaw(int64(gwei)).BigInt()
}

// TargetBalance returns the target balance to fund a contract to.
func (t FundThresholds) TargetBalance() *big.Int {
gwei := t.targetEther * params.GWei
if gwei < 1 {
panic("ether float64 must be greater than 1 Gwei")
}

return math.NewInt(params.GWei).MulRaw(int64(gwei)).BigInt()
}

// WithdrawThresholds defines the thresholds for withdrawing from a contract.
type WithdrawThresholds struct {
maxEther float64
}

// MaxBalance returns the max balance a contract can have before a withdrawal.
func (t WithdrawThresholds) MaxBalance() *big.Int {
gwei := t.maxEther * params.GWei

if gwei < 1 {
panic("ether float64 must be greater than 1 Gwei")
}

return math.NewInt(params.GWei).MulRaw(int64(gwei)).BigInt()
}
60 changes: 0 additions & 60 deletions lib/contracts/fund.go

This file was deleted.

9 changes: 8 additions & 1 deletion monitor/contract/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var (
Namespace: "monitor",
Subsystem: "contract",
Name: "balance_ether",
Help: "The balance of the contract on a specific chain in ether. Alert if low.",
Help: "The balance of the contract on a specific chain in ether. Alert if low or high.",
}, []string{"chain", "name"})

contractBalanceLow = promauto.NewGaugeVec(prometheus.GaugeOpts{
Expand All @@ -19,4 +19,11 @@ var (
Name: "balance_low",
Help: "Constant gauge indicating whether the contract balance is below the minimum threshold (1=true,0=false)",
}, []string{"chain", "name"})

contractBalanceHigh = promauto.NewGaugeVec(prometheus.GaugeOpts{
Namespace: "monitor",
Subsystem: "contract",
Name: "balance_high",
Help: "Constant gauge indicating whether the contract balance is above the maximum threshold (1=true,0=false)",
}, []string{"chain", "name"})
)
37 changes: 25 additions & 12 deletions monitor/contract/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func StartMonitoring(ctx context.Context, network netconf.Network, endpoints xch
contracts.UseStagingOmniRPC(omniEVMRPC)
}

toFund, err := contracts.ToFund(ctx, network.ID)
allContracts, err := contracts.ToMonitor(ctx, network.ID)
if err != nil {
log.Error(ctx, "Failed to get contract addreses to monitor - skipping monitoring", err)
return nil
Expand All @@ -43,8 +43,8 @@ func StartMonitoring(ctx context.Context, network netconf.Network, endpoints xch
for _, chain := range network.EVMChains() {
isOmniEVM := chain.ID == network.ID.Static().OmniExecutionChainID

for _, contract := range toFund {
if contract.OnlyOmniEVM && !isOmniEVM {
for _, contract := range allContracts {
if (contract.OnlyOmniEVM && !isOmniEVM) || (contract.NotOmniEVM && isOmniEVM) {
continue
}

Expand All @@ -58,7 +58,7 @@ func StartMonitoring(ctx context.Context, network netconf.Network, endpoints xch
// monitorContractForever blocks and periodically monitors the contract for the given chain.
func monitorContractForever(
ctx context.Context,
contract contracts.WithFundThreshold,
contract contracts.Contract,
chainName string,
client ethclient.Client,
) {
Expand All @@ -68,7 +68,7 @@ func monitorContractForever(
"address", contract.Address,
)

log.Info(ctx, "Monitoring account")
log.Info(ctx, "Monitoring contract")

ticker := time.NewTicker(time.Second * 30)
defer ticker.Stop()
Expand All @@ -83,17 +83,16 @@ func monitorContractForever(
return
} else if err != nil {
log.Warn(ctx, "Monitoring contract failed (will retry)", err)

continue
}
}
}
}

// monitorContractOnce monitors contract for the given chain.
// monitorContractOnce monitors the contract for the given chain.
func monitorContractOnce(
ctx context.Context,
contract contracts.WithFundThreshold,
contract contracts.Contract,
chainName string,
client ethclient.Client,
) error {
Expand All @@ -106,14 +105,28 @@ func monitorContractOnce(
bf, _ := balance.Float64()
balanceEth := bf / params.Ether

// Always set the balance metric
contractBalance.WithLabelValues(chainName, contract.Name).Set(balanceEth)

var isLow float64
if balance.Cmp(contract.Thresholds.MinBalance()) <= 0 {
isLow = 1
// Handle funding threshold checks, if any
if contract.FundThresholds != nil {
var isLow float64
if balance.Cmp(contract.FundThresholds.MinBalance()) <= 0 {
isLow = 1
}

contractBalanceLow.WithLabelValues(chainName, contract.Name).Set(isLow)
}

contractBalanceLow.WithLabelValues(chainName, contract.Name).Set(isLow)
// Handle withdrawal threshold checks, if any
if contract.WithdrawThresholds != nil {
var isHigh float64
if balance.Cmp(contract.WithdrawThresholds.MaxBalance()) >= 0 {
isHigh = 1
}

contractBalanceHigh.WithLabelValues(chainName, contract.Name).Set(isHigh)
}

return nil
}

0 comments on commit 6d4c649

Please sign in to comment.