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: 2 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ func init() {
rootCmd.Flags().Uint32("auto-unbonding-amount", 0, "Amount of tokens in loya to unbond each unbonding transaction (0 = disabled)")
rootCmd.Flags().String("auto-unbonding-max-stake-percentage", "0.0", "Maximum percentage of stake to unbond each unbonding transaction (0 = disabled, 1.0 = 100%). If unbonding amount exceeds this percentage, we will skip the unbonding transaction until it exceeds this percentage again.")
rootCmd.Flags().Duration("refresh-gas-estimates-interval", 12*time.Hour, "Interval for resetting cached gas estimates and gas-adjustment levels (<=0 disables)")
// Remote signer: when set, tx signing is delegated to the remote signer service instead of the local keyring
rootCmd.Flags().String("remote-signer-addr", "", "gRPC address of the remote signer service (e.g. localhost:9191). When set, tx signing uses the remote signer instead of the local keyring.")

// Auto-bridge: keep wallet at a fixed balance by bridging the excess to Ethereum
rootCmd.Flags().Uint64(daemonflags.FlagAutoBalanceToKeep, 0, "Keep this amount of loya in the wallet; bridge any excess to Ethereum at --auto-balance-execution-time (0 = disabled)")
Expand Down
32 changes: 20 additions & 12 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module github.com/tellor-io/layer-daemons

go 1.23.2
go 1.24.0

toolchain go1.23.7
toolchain go1.24.1

require (
cosmossdk.io/errors v1.0.2
Expand Down Expand Up @@ -30,7 +30,7 @@ require (
github.com/tellor-io/layer v0.0.0-20260102193944-693854ff6bff
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a
google.golang.org/grpc v1.72.2
google.golang.org/grpc v1.79.3
gopkg.in/typ.v4 v4.3.0
)

Expand Down Expand Up @@ -87,8 +87,8 @@ require (
go.uber.org/mock v0.5.2 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
golang.org/x/arch v0.15.0 // indirect
golang.org/x/text v0.27.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
golang.org/x/text v0.32.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

Expand Down Expand Up @@ -149,7 +149,7 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/flatbuffers v1.12.1 // indirect
github.com/google/flatbuffers v2.0.8+incompatible // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/google/s2a-go v0.1.8 // indirect
Expand Down Expand Up @@ -230,16 +230,16 @@ require (
go.opentelemetry.io/otel/metric v1.34.0 // indirect
go.opentelemetry.io/otel/trace v1.34.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.40.0
golang.org/x/net v0.41.0 // indirect
golang.org/x/crypto v0.46.0
golang.org/x/net v0.48.0 // indirect
golang.org/x/oauth2 v0.26.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/term v0.33.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/term v0.38.0 // indirect
golang.org/x/time v0.9.0 // indirect
google.golang.org/api v0.215.0 // indirect
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.2 // indirect
nhooyr.io/websocket v1.8.10 // indirect
Expand All @@ -257,3 +257,11 @@ replace (
replace cosmossdk.io/collections => cosmossdk.io/collections v0.4.0

replace cosmossdk.io/core => cosmossdk.io/core v0.11.0

require github.com/tellor-io/bridge-remote-signer/api v0.0.0

replace github.com/tellor-io/bridge-remote-signer/api => ./vendor-api

// Pin grpc to the version already used by this module to prevent the bridge-remote-signer/api
// dependency from upgrading it (which would pull in incompatible otel semconv versions).
replace google.golang.org/grpc => google.golang.org/grpc v1.72.2
1,128 changes: 1,035 additions & 93 deletions go.sum

Large diffs are not rendered by default.

82 changes: 52 additions & 30 deletions reporter/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ type Client struct {
rpcMu sync.RWMutex
rpcManager *rpcEndpointManager

remoteSignerConn *grpc.ClientConn // non-nil when --remote-signer-addr is set

wg sync.WaitGroup
broadcastWg sync.WaitGroup // Tracks goroutines in BroadcastTxMsgToChain
stopOnce sync.Once
Expand Down Expand Up @@ -394,41 +396,54 @@ func (c *Client) Start(
encodingConfig := CreateEncodingConfig()
c.cosmosCtx = c.cosmosCtx.WithCodec(encodingConfig.Codec).WithInterfaceRegistry(encodingConfig.InterfaceRegistry).WithTxConfig(encodingConfig.TxConfig)

keyringInput, usingPasswordFile, err := keyringReader()
if err != nil {
return err
}
if err := validateKeyringBackendConfig(kb, usingPasswordFile); err != nil {
return err
}
c.logger.Info("Using keyring backend", "backend", kb)
kr, err := keyring.New("", kb, homeDir, keyringInput, encodingConfig.Codec)
if err != nil {
if usingPasswordFile {
return fmt.Errorf("%w: could not initialize keyring backend %q: %w", ErrKeyringPasswordFile, kb, err)
remoteSignerAddr := viper.GetString("remote-signer-addr")
if remoteSignerAddr != "" {
// Use remote signer for tx signing — no local private key needed.
c.logger.Info("Using remote signer for tx signing", "addr", remoteSignerAddr)
kr, signerAccAddr, signerConn, err := newKeyringFromRemoteSigner(ctx, keyName, remoteSignerAddr)
if err != nil {
return fmt.Errorf("failed to initialize remote signer keyring: %w", err)
}
return fmt.Errorf("could not initialize keyring backend %q: %w", kb, err)
}
record, err := kr.Key(keyName)
if err != nil {
if usingPasswordFile {
return fmt.Errorf("%w: account %q could not be read from keyring backend %q: %w", ErrKeyringPasswordFile, keyName, kb, err)
// Store the connection so it gets closed during shutdown.
c.remoteSignerConn = signerConn
c.cosmosCtx = c.cosmosCtx.WithKeyring(kr)
c.cosmosCtx = c.cosmosCtx.WithFrom(keyName).WithFromName(keyName).WithFromAddress(signerAccAddr)
} else {
keyringInput, usingPasswordFile, err := keyringReader()
if err != nil {
return err
}
return fmt.Errorf("account %q could not be read from keyring backend %q: %w", keyName, kb, err)
}
addr, err := record.GetAddress()
if err != nil {
return err
}
if usingPasswordFile {
if err := validateKeyringAccountUnlocked(kr, keyName); err != nil {
if err := validateKeyringBackendConfig(kb, usingPasswordFile); err != nil {
return err
}
c.logger.Info("KEYRING_PASSWORD_FILE unlocked keyring account successfully", "account", keyName, "address", addr.String())
c.logger.Info("Using keyring backend", "backend", kb)
kr, err := keyring.New("", kb, homeDir, keyringInput, encodingConfig.Codec)
if err != nil {
if usingPasswordFile {
return fmt.Errorf("%w: could not initialize keyring backend %q: %w", ErrKeyringPasswordFile, kb, err)
}
return fmt.Errorf("could not initialize keyring backend %q: %w", kb, err)
}
record, err := kr.Key(keyName)
if err != nil {
if usingPasswordFile {
return fmt.Errorf("%w: account %q could not be read from keyring backend %q: %w", ErrKeyringPasswordFile, keyName, kb, err)
}
return fmt.Errorf("account %q could not be read from keyring backend %q: %w", keyName, kb, err)
}
addr, err := record.GetAddress()
if err != nil {
return err
}
if usingPasswordFile {
if err := validateKeyringAccountUnlocked(kr, keyName); err != nil {
return err
}
c.logger.Info("KEYRING_PASSWORD_FILE unlocked keyring account successfully", "account", keyName, "address", addr.String())
}
c.cosmosCtx = c.cosmosCtx.WithKeyring(kr)
c.cosmosCtx = c.cosmosCtx.WithFrom(keyName).WithFromName(keyName).WithFromAddress(addr)
}

c.cosmosCtx = c.cosmosCtx.WithKeyring(kr)
c.cosmosCtx = c.cosmosCtx.WithFrom(keyName).WithFromName(keyName).WithFromAddress(addr)
c.accAddr = c.cosmosCtx.GetFromAddress()

StartReporterDaemonTaskLoop(
Expand Down Expand Up @@ -908,6 +923,13 @@ func (c *Client) Stop() {
}
}

// Close remote signer connection if used
if c.remoteSignerConn != nil {
if err := c.remoteSignerConn.Close(); err != nil {
c.logger.Error("Failed to close remote signer connection", "error", err)
}
}

c.logger.Info("ReporterClient: stopped")
})
}
Loading
Loading