You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
**Note:** Daemon services code was adopted from dydx [](https://github.com/dydxprotocol/v4-chain/tree/main/protocol/daemons) and reconfigured.
3
+
**Note:** Daemon services code was adopted from [dYdX](https://github.com/dydxprotocol/v4-chain/tree/main/protocol/daemons) and reconfigured.
4
+
5
+
## Configuration
6
+
7
+
The daemon loads environment variables from the current directory's `.env` file, or from `../.env` when run from a subdirectory. See [`env.example`](./env.example) for a complete starting point.
8
+
9
+
Most CLI flags can also be provided as environment variables by uppercasing the flag name and replacing `-` or `.` with `_`, for example `--keyring-backend` becomes `KEYRING_BACKEND`. `LAYER_HOME` is preferred for the Layer home directory so the daemon does not accidentally use the shell's `HOME`.
10
+
11
+
Layer endpoint configuration can be provided with comma-separated environment variables:
-`RPC_NODES` / `--node` configures CometBFT RPC. The reporter uses this for startup chain ID validation, block/status polling, transaction broadcast, and transaction lookup while waiting for inclusion.
24
+
25
+
Endpoint env vars take precedence over the existing CLI flags:
26
+
27
+
-`RPC_NODES` is preferred over `--node`.
28
+
-`GRPC_NODES` is preferred over `--grpc`.
29
+
- If an env var is unset, the daemon preserves the old behavior by using the matching flag value as a single endpoint.
30
+
31
+
At startup, the daemon checks the configured gRPC and CometBFT RPC endpoints for a matching chain ID and starts with the first healthy matching endpoints. The reporter keeps both endpoint lists and falls back to later nodes for network/client failures. gRPC fallback is used for reporter chain queries, while RPC fallback is used for status checks, transaction lookup, and transaction broadcast. The reporter also periodically probes the primary endpoints and switches back when they are healthy again. It does not switch endpoints for semantic chain failures such as out-of-gas responses, non-zero tx result codes, or normal tx-not-found polling.
32
+
33
+
The pricefeed client is started with the selected gRPC endpoint only. Endpoint-list fallback currently applies to the reporter client's chain query and transaction paths, not to the pricefeed client.
34
+
35
+
Ethereum JSON-RPC configuration uses the same comma-separated primary/fallback pattern:
`BRIDGE_CHAIN_RPC_NODES` is used by token bridge deposit monitoring. The first endpoint is tried first; later entries are ordered fallbacks.
42
+
43
+
Ethereum mainnet custom query contract reads use the built-in mainnet endpoint templates by default. If `BRIDGE_CHAIN_RPC_NODES` points at a non-mainnet bridge chain such as Sepolia, set `ETH_MAINNET_RPC_NODES` to a comma-separated Ethereum mainnet endpoint list for custom queries.
44
+
45
+
Custom query API keys are read from the generated `custom_query_config.toml` entries that reference environment placeholders. The current built-in templates use `CMC_PRO_API_KEY`, `CGPRO_API_KEY`, and `SUBGRAPH_API_KEY`.
4
46
5
47
## Task loops
6
48
7
49
## PriceFetcher
8
50
9
-
- Will query exchanges for prices once or multiple times based on wether the api supports single vs multi markets; ie wether an api needs to be queried for each pair individually or can return multiple pairs at once,[See here for exchange details](./constants/static_exchange_details.go).
51
+
- Will query exchanges for prices once or multiple times based on whether the API supports single vs multi markets; i.e. whether an API needs to be queried for each pair individually or can return multiple pairs at once.[See here for exchange details](./constants/static_exchange_details.go).
10
52
11
53
## PriceEncoder
12
54
13
-
- Will update cache with the queried prices and encode appropriately also make adjustments as necessary based on if adjustByMarket is defined.
55
+
- Will update the cache with queried prices, encode them appropriately, and make adjustments when `adjustByMarket` is defined.
14
56
15
57
### Configuration
16
58
@@ -34,7 +76,7 @@ example:
34
76
35
77
```go
36
78
[[market_params]]
37
-
ExchangeConfigJson = "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"\\\"ETHBTC\\\"\"},{\"exchangeName\":\"Bitfinex\",\"ticker\":\"tETHBTC\",\"adjustByMarket\":\"BTC-USD\"}]}"//this is just an example to show how to use adjustByMarket. you can use ETH-USD without adjustbymarket
79
+
ExchangeConfigJson = "{\"exchanges\":[{\"exchangeName\":\"Binance\",\"ticker\":\"\\\"ETHBTC\\\"\"},{\"exchangeName\":\"Bitfinex\",\"ticker\":\"tETHBTC\",\"adjustByMarket\":\"BTC-USD\"}]}"//This is an example showing how to use adjustByMarket. You can use ETH-USD without adjustByMarket.
38
80
Exponent = -6
39
81
Id = 2
40
82
MinExchanges = 1
@@ -51,7 +93,7 @@ type MarketParam struct {
51
93
Pairstring
52
94
// Static value. The exponent of the price.
53
95
// For example if `Exponent == -5` then a `Value` of `1,000,000,000`
54
-
// represents “$10,000`. Therefore `10 ^ Exponent` represents the smallest
96
+
// represents "$10,000". Therefore `10 ^ Exponent` represents the smallest
55
97
// price step (in dollars) that can be recorded.
56
98
Exponentint32
57
99
// The minimum number of exchanges that should be reporting a live price for
@@ -63,7 +105,7 @@ type MarketParam struct {
63
105
// A string of json that encodes the configuration for resolving the price
64
106
// of this market on various exchanges.
65
107
ExchangeConfigJsonstring
66
-
// Query data is the market pair represention in layer
108
+
// Query data is the market pair representation in layer
67
109
QueryDatastring
68
110
}
69
111
```
@@ -74,10 +116,54 @@ A price is valid by default up to 30 seconds; to change this to a different defa
74
116
**Also:** Config files are written to homedir/.layer/config/.
75
117
To change/add exchange details or market pairs edit the files `pricefeed_exchange_config.toml` or `market_params.toml` respectively.
76
118
119
+
## Keyring Password File
120
+
121
+
When running the reporter daemon with `--keyring-backend file`, set `KEYRING_PASSWORD_FILE` to a file containing the keyring password. This lets the daemon unlock the account without requiring an interactive terminal prompt.
122
+
123
+
For this systemd file-keyring setup, set `LAYER_HOME` to the same home directory that contains the daemon config and keyring files. This keeps the non-interactive service from resolving `home` from the service user's shell environment instead of the intended Layer home.
sudo sh -c 'printf "%s\n" "YOUR_KEYRING_PASSWORD" > /etc/layer-daemons/reporter-keyring-password'
145
+
```
146
+
147
+
Make sure the service `User` can read the file. When `KEYRING_PASSWORD_FILE` is set, startup fails and the daemon exits if the file cannot be read, is empty, or cannot unlock the configured `--from` account. If `KEYRING_PASSWORD_FILE` is not set, the daemon falls back to reading the keyring password from stdin.
148
+
149
+
## Reward Withdrawals And Auto-Unbonding
150
+
151
+
The reporter periodically withdraws earned tips/rewards with `MsgWithdrawTip`. The interval is configured by `WITHDRAW_FREQUENCY` in seconds and defaults to `43200` (12 hours). By default, the validator operator address is derived from the reporter account address. If the reporter account is delegated to a different validator, set `REPORTERS_VALIDATOR_ADDRESS` to that validator's `tellorvaloper...` address.
152
+
153
+
Auto-unbonding is optional and can be configured by CLI flags or equivalent environment variables:
154
+
155
+
| Flag | Environment | Type | Default | Description |
|`--auto-unbonding-frequency`|`AUTO_UNBONDING_FREQUENCY`| uint32 |`0`| Enables unbonding every N days (`0` = disabled, valid enabled range is 1-21). |
158
+
|`--auto-unbonding-amount`|`AUTO_UNBONDING_AMOUNT`| uint32 |`0`| Amount of `loya` to unbond each time. Required when frequency is enabled. |
159
+
|`--auto-unbonding-max-stake-percentage`|`AUTO_UNBONDING_MAX_STAKE_PERCENTAGE`| decimal string |`0.0`| Optional cap from `0.0` to `1.0`; if the configured amount exceeds this share of stake, the unbond is skipped. |
160
+
161
+
Gas estimates are cached per transaction type. `--refresh-gas-estimates-interval` / `REFRESH_GAS_ESTIMATES_INTERVAL` resets cached estimates and gas-adjustment levels periodically; it defaults to `12h`, and values `<=0` disable the refresh loop.
162
+
77
163
### Median Server
78
164
79
-
Median server was added for a way to query median values that were from an endpoint or cli. See usage [here](../x/oracle/client/cli/query_all_get_median.go).
80
-
All median values or median value given query data using the following commands respectively.
165
+
The median server can query median values from an endpoint or the CLI. See usage [here](../x/oracle/client/cli/query_all_get_median.go).
166
+
Query all median values, or a median value for specific query data, using the following commands respectively.
|`--price-guard-enabled`| bool | Enables the price guard mechanism | No |
120
-
|`--price-guard-threshold`| float64 | Maximum allowed percentage change (e.g., 0.5 = 50%). Submissions exceeding this change from the last reported price will be blocked. | Yes |
121
-
|`--price-guard-max-age`| duration | Time after which a stored price is considered expired (e.g., "1h"). If the last price is expired, the new price is accepted regardless of deviation. | Yes |
122
-
|`--price-guard-update-on-blocked`| bool | If true, updates the internal "last known price" to the new value even if submission was blocked. If false, keeps the old price as the baseline. | Yes |
|`--price-guard-enabled`|`PRICE_GUARD_ENABLED`|bool | Enables the price guard mechanism.| No |
206
+
|`--price-guard-threshold`|`PRICE_GUARD_THRESHOLD`|float64 | Maximum allowed percentage change (e.g.`0.5` = 50%). Submissions exceeding this change from the last reported price are blocked. | Yes |
207
+
|`--price-guard-max-age`|`PRICE_GUARD_MAX_AGE`|duration | Time after which a stored price is considered expired (e.g.`1h`). If the last price is expired, the new price is accepted regardless of deviation. | Yes |
208
+
|`--price-guard-update-on-blocked`|`PRICE_GUARD_UPDATE_ON_BLOCKED`|bool | If true, updates the internal "last known price" to the new value even if submission was blocked. If false, keeps the old price as the baseline. | Yes |
123
209
124
210
### Notes
125
211
@@ -131,3 +217,46 @@ The Price Guard is a safety mechanism that prevents the reporter from submitting
131
217
4.**Update on Blocked:**
132
218
- If `true`: A blocked price becomes the new baseline for future checks.
133
219
- If `false`: The old price remains the baseline; future submissions must be within threshold of the *old* price.
220
+
221
+
## Auto balance-to-keep
222
+
223
+
The reporter daemon can keep a target **loya** balance in the reporter wallet and automatically bridge any excess to Ethereum once per day. This uses Layer’s `MsgWithdrawTokens` bridge message (`isBridge` gas bucket, same tx pipeline as other bridge operations).
224
+
225
+
### Flags
226
+
227
+
| Flag | Environment | Type | Default | Description |
|`--auto-balance-to-keep`|`AUTO_BALANCE_TO_KEEP`| uint64 |`0`| Target wallet balance in **loya** (`0` = disabled). Any amount above this, minus the gas reserve below, is bridged. |
230
+
|`--auto-balance-execution-time`|`AUTO_BALANCE_EXECUTION_TIME`| string |`00:00`| UTC time to check balance and bridge, format **`HH:MM`** with hour 0-23 and minute 0-59 (e.g. `03:00`, `15:30`). |
231
+
|`--auto-balance-bridge-to-eth-addr`|`AUTO_BALANCE_BRIDGE_TO_ETH_ADDR`| string |`""`| Ethereum recipient for bridged tokens. Required when `--auto-balance-to-keep > 0`. May include or omit the `0x` prefix. Validated with standard hex address checks at startup. |
232
+
233
+
### Behavior
234
+
235
+
1.**Schedule:** Once per UTC day at `--auto-balance-execution-time`, the daemon queries the reporter wallet's `loya` balance.
236
+
2.**Amount:**`bridge_amount = wallet_balance - auto-balance-to-keep - 1_000_000` (a fixed **1 TRB** reserve in loya is left for future gas). If `bridge_amount <= 0`, nothing is sent.
237
+
3.**Broadcast:** The transaction uses the shared broadcast path with RPC endpoint fallback and gas-adjustment retries for out-of-gas responses. Other failures are logged; the next balance check happens at the next scheduled UTC time.
238
+
4.**Shutdown:** Bridge txs are enqueued with `trySend` so shutdown does not panic on a closed channel.
239
+
240
+
### Startup validation
241
+
242
+
When `--auto-balance-to-keep > 0`, the reporter **fails to start** if:
243
+
244
+
-`--auto-balance-bridge-to-eth-addr` is missing or not a valid Ethereum address
245
+
-`--auto-balance-execution-time` is not valid `HH:MM` (hour 0-23, minute 0-59)
246
+
247
+
### Example
248
+
249
+
Keep 5 TRB in the wallet (5_000_000 loya), run the check daily at 03:00 UTC, and bridge excess to an Ethereum address:
0 commit comments