Skip to content

Commit 700ebef

Browse files
curryxbocorey
andauthored
Add external sign (#844)
Co-authored-by: corey <[email protected]>
1 parent 3ee14af commit 700ebef

File tree

10 files changed

+599
-153
lines changed

10 files changed

+599
-153
lines changed

MakefileEks.mk

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ build-bk-prod-morph-prod-mainnet-to-morph-token-price-oracle:
121121
if [ ! -d dist ]; then mkdir -p dist; fi
122122
env GO111MODULE=on CGO_LDFLAGS="-ldl" CGO_ENABLED=1 go build -v $(LDFLAGS) -o token-price-oracle/token-price-oracle ./token-price-oracle/cmd
123123
cp token-price-oracle/token-price-oracle dist/
124+
aws s3 cp s3://morph-0582-morph-technical-department-mainnet-data/morph-setup/secret-manager-wrapper.tar.gz ./
125+
tar -xvzf secret-manager-wrapper.tar.gz
124126

125127

126128
start-bk-prod-morph-prod-mainnet-to-morph-token-price-oracle:
@@ -202,4 +204,4 @@ build-bk-prod-morph-prod-testnet-to-morph-staking-oracle-holesky:
202204
tar -xvzf secret-manager-wrapper.tar.gz
203205

204206
start-bk-prod-morph-prod-testnet-to-morph-staking-oracle-holesky:
205-
/data/secret-manager-wrapper ./staking-oracle
207+
/data/secret-manager-wrapper ./staking-oracle

token-price-oracle/README.md

Lines changed: 141 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,173 +1,190 @@
1-
# Gas Price Oracle
1+
# Token Price Oracle
22

3-
Gas Price Oracle service monitors L1 gas prices and updates the GasPriceOracle contract on L2.
3+
Token Price Oracle service monitors token prices and updates the price ratio between tokens and ETH to L2 on-chain contracts, enabling Alt Fee Token functionality.
44

55
## Features
66

7-
- **L1 Base Fee Update**: Monitors L1 base fee and blob base fee, updates to L2
8-
- **Scalar Update**: Calculates and updates commit scalar and blob scalar
9-
- **Transaction Manager**: Serializes all contract updates to avoid nonce conflicts
10-
- **Metrics Monitoring**: Exposes Prometheus metrics
11-
- **Flags Configuration**: Uses `urfave/cli` for configuration management (supports both CLI flags and environment variables)
7+
- **Real-time Price Monitoring**: Fetches token USD prices from exchange APIs (Bitget)
8+
- **Price Ratio Calculation**: Computes price ratio between tokens and ETH
9+
- **Threshold-based Updates**: Only updates on-chain when price change exceeds threshold, saving Gas
10+
- **Batch Updates**: Updates multiple token prices in a single `batchUpdatePrices` transaction
11+
- **Fallback Mechanism**: Supports automatic switching between multiple data sources
12+
- **Transaction Management**: Prevents nonce conflicts, supports local and external signing
13+
- **Prometheus Monitoring**: Provides operational metrics
1214

13-
## Configuration
14-
15-
The service uses flags that can be set either via command line or environment variables (with `GAS_ORACLE_` prefix).
16-
17-
### Required Flags
18-
19-
| Flag | Env Var | Description |
20-
| --------------------- | --------------------------- | ------------------------------- |
21-
| `--l1-eth-rpc` | `GAS_ORACLE_L1_ETH_RPC` | L1 RPC endpoint |
22-
| `--l2-eth-rpc` | `GAS_ORACLE_L2_ETH_RPC` | L2 RPC endpoint |
23-
| `--l1-beacon-rpc` | `GAS_ORACLE_L1_BEACON_RPC` | L1 Beacon Chain API endpoint |
24-
| `--l1-rollup-address` | `GAS_ORACLE_L1_ROLLUP` | L1 Rollup contract address |
25-
| `--private-key` | `GAS_ORACLE_L2_PRIVATE_KEY` | Private key for L2 transactions |
26-
27-
### Optional Flags
15+
## Quick Start
2816

29-
| Flag | Env Var | Default | Description |
30-
| ------------------------------- | ---------------------------------- | --------------- | --------------------------- |
31-
| `--l2-gas-price-oracle-address` | `GAS_ORACLE_L2_GAS_PRICE_ORACLE` | `0x5300...0002` | L2 GasPriceOracle contract |
32-
| `--gas-threshold` | `GAS_ORACLE_GAS_THRESHOLD` | `10` | Update threshold percentage |
33-
| `--interval` | `GAS_ORACLE_INTERVAL` | `6s` | Base fee update interval |
34-
| `--overhead-interval` | `GAS_ORACLE_OVERHEAD_INTERVAL` | `10` | Scalar update frequency |
35-
| `--txn-per-batch` | `GAS_ORACLE_TXN_PER_BATCH` | `50` | Expected txs per batch |
36-
| `--log-level` | `GAS_ORACLE_LOG_LEVEL` | `info` | Log level |
37-
| `--log-filename` | `GAS_ORACLE_LOG_FILENAME` | - | Log file path |
38-
| `--metrics-server-enable` | `GAS_ORACLE_METRICS_SERVER_ENABLE` | `false` | Enable metrics server |
39-
| `--metrics-hostname` | `GAS_ORACLE_METRICS_HOSTNAME` | `0.0.0.0` | Metrics server host |
40-
| `--metrics-port` | `GAS_ORACLE_METRICS_PORT` | `6060` | Metrics server port |
41-
42-
## Usage
43-
44-
### Command Line
17+
### Environment Variables (Local Signing Mode)
4518

4619
```bash
47-
./bin/token-price-oracle \
48-
--l1-eth-rpc https://ethereum-rpc.com \
49-
--l2-eth-rpc https://morph-l2-rpc.com \
50-
--l1-beacon-rpc https://beacon-api.com \
51-
--l1-rollup-address 0x... \
52-
--private-key 0x... \
53-
--metrics-server-enable \
54-
--log-level debug
20+
# Required
21+
export TOKEN_PRICE_ORACLE_L2_ETH_RPC="https://rpc.morphl2.io"
22+
export TOKEN_PRICE_ORACLE_PRIVATE_KEY="0x..." # Required for local signing only
23+
export TOKEN_PRICE_ORACLE_BITGET_API_BASE_URL="https://api.bitget.com"
24+
export TOKEN_PRICE_ORACLE_TOKEN_MAPPING_BITGET="1:BTCUSDT,2:ETHUSDT"
25+
26+
# Optional
27+
export TOKEN_PRICE_ORACLE_PRICE_UPDATE_INTERVAL="1m"
28+
export TOKEN_PRICE_ORACLE_PRICE_THRESHOLD="100" # 1% (100 bps)
29+
export TOKEN_PRICE_ORACLE_METRICS_SERVER_ENABLE="true"
30+
export TOKEN_PRICE_ORACLE_METRICS_PORT="6060"
31+
export TOKEN_PRICE_ORACLE_LOG_LEVEL="info"
5532
```
5633

57-
### Environment Variables
58-
59-
```bash
60-
export GAS_ORACLE_L1_ETH_RPC="https://ethereum-rpc.com"
61-
export GAS_ORACLE_L2_ETH_RPC="https://morph-l2-rpc.com"
62-
export GAS_ORACLE_L1_BEACON_RPC="https://beacon-api.com"
63-
export GAS_ORACLE_L1_ROLLUP="0x..."
64-
export GAS_ORACLE_L2_PRIVATE_KEY="0x..."
65-
export GAS_ORACLE_METRICS_SERVER_ENABLE=true
66-
export GAS_ORACLE_LOG_LEVEL=info
67-
68-
./bin/token-price-oracle
69-
```
34+
> **Note**: `PRIVATE_KEY` is only required when using local signing mode. For production, use [External Signing](#external-signing-recommended-for-production) instead.
7035
71-
## Build and Run
72-
73-
**Note**: This project uses Go workspace and depends on `../bindings` module.
36+
### Build and Run
7437

7538
```bash
7639
# Build
7740
make build
7841

7942
# Run
80-
make run
81-
82-
# Test
83-
make test
43+
./build/bin/token-price-oracle
8444

85-
# Test Bitget price feed (requires network)
86-
go test ./client -run TestBitgetPriceFeed -v
87-
88-
# Docker
45+
# Or use Docker
8946
make docker-build
9047
docker run -d \
91-
-e GAS_ORACLE_L1_ETH_RPC="..." \
92-
-e GAS_ORACLE_L2_ETH_RPC="..." \
93-
-e GAS_ORACLE_L1_BEACON_RPC="..." \
94-
-e GAS_ORACLE_L1_ROLLUP="0x..." \
95-
-e GAS_ORACLE_L2_PRIVATE_KEY="0x..." \
48+
-e TOKEN_PRICE_ORACLE_L2_ETH_RPC="..." \
49+
-e TOKEN_PRICE_ORACLE_PRIVATE_KEY="..." \
50+
-e TOKEN_PRICE_ORACLE_BITGET_API_BASE_URL="..." \
51+
-e TOKEN_PRICE_ORACLE_TOKEN_MAPPING_BITGET="..." \
9652
morph/token-price-oracle:latest
9753
```
9854

99-
## Monitoring
55+
## Configuration
10056

101-
When metrics server is enabled, it exposes metrics at `<hostname>:<port>/metrics`:
57+
### Required (All Modes)
10258

103-
- `l1_base_fee` - L1 base fee (Gwei)
104-
- `l1_base_fee_on_l2` - L1 base fee on L2
105-
- `l1_blob_base_fee_on_l2` - L1 blob base fee on L2
106-
- `commit_scalar` - Commit scalar value
107-
- `blob_scalar` - Blob scalar value
108-
- `txn_per_batch` - Transactions per batch
109-
- `gas_oracle_owner_balance` - Oracle account balance
110-
- `base_fee_update_count` - Total base fee updates
111-
- `scalar_update_count` - Total scalar updates
112-
- `update_errors_total` - Update errors by type
59+
| Environment Variable | Description |
60+
|---------------------|-------------|
61+
| `TOKEN_PRICE_ORACLE_L2_ETH_RPC` | L2 node RPC endpoint |
62+
| `TOKEN_PRICE_ORACLE_BITGET_API_BASE_URL` | Bitget API base URL |
63+
| `TOKEN_PRICE_ORACLE_TOKEN_MAPPING_BITGET` | TokenID to trading pair mapping |
11364

114-
Health check endpoint: `<hostname>:<port>/health`
65+
### Required (Local Signing Mode Only)
11566

116-
## Architecture
67+
| Environment Variable | Description |
68+
|---------------------|-------------|
69+
| `TOKEN_PRICE_ORACLE_PRIVATE_KEY` | Signing private key (not needed if using external signing) |
11770

118-
```
119-
gas-price-oracle/
120-
├── cmd/ # Main entry point
121-
├── flags/ # CLI flags definitions
122-
├── config/ # Configuration from flags
123-
├── updater/ # Update implementations
124-
│ ├── basefee.go # Base fee updater
125-
│ ├── scalar.go # Scalar updater
126-
│ └── tx_manager.go # Transaction manager (prevents nonce conflicts)
127-
├── client/ # Client wrappers
128-
├── calc/ # Calculation logic
129-
└── metrics/ # Prometheus metrics
71+
### Optional
72+
73+
| Environment Variable | Default | Description |
74+
|---------------------|---------|-------------|
75+
| `TOKEN_PRICE_ORACLE_PRICE_UPDATE_INTERVAL` | `1m` | Price update interval |
76+
| `TOKEN_PRICE_ORACLE_PRICE_THRESHOLD` | `100` | Update threshold (basis points, 100=1%) |
77+
| `TOKEN_PRICE_ORACLE_PRICE_FEED_PRIORITY` | `bitget` | Price feed priority |
78+
| `TOKEN_PRICE_ORACLE_METRICS_SERVER_ENABLE` | `false` | Enable metrics server |
79+
| `TOKEN_PRICE_ORACLE_METRICS_HOSTNAME` | `0.0.0.0` | Metrics server hostname |
80+
| `TOKEN_PRICE_ORACLE_METRICS_PORT` | `6060` | Metrics server port |
81+
| `TOKEN_PRICE_ORACLE_LOG_LEVEL` | `info` | Log level |
82+
| `TOKEN_PRICE_ORACLE_LOG_FILENAME` | - | Log file path |
83+
84+
### External Signing (Recommended for Production)
85+
86+
| Environment Variable | Description |
87+
|---------------------|-------------|
88+
| `TOKEN_PRICE_ORACLE_EXTERNAL_SIGN` | Enable external signing (`true`/`false`) |
89+
| `TOKEN_PRICE_ORACLE_EXTERNAL_SIGN_ADDRESS` | Signing account address |
90+
| `TOKEN_PRICE_ORACLE_EXTERNAL_SIGN_APPID` | External signing service AppID |
91+
| `TOKEN_PRICE_ORACLE_EXTERNAL_SIGN_CHAIN` | Chain identifier |
92+
| `TOKEN_PRICE_ORACLE_EXTERNAL_SIGN_URL` | External signing service URL |
93+
| `TOKEN_PRICE_ORACLE_EXTERNAL_SIGN_RSA_PRIV` | RSA private key (PEM format) |
94+
95+
## Price Calculation
13096

131-
Uses: ../bindings/bindings (project root contract bindings)
97+
### Price Ratio Formula
98+
99+
```
100+
priceRatio = tokenScale × tokenPriceUSD × 10^(18 - tokenDecimals) / ethPriceUSD
132101
```
133102

134-
## Key Components
103+
### Threshold
135104

136-
### Transaction Manager
105+
Threshold is specified in basis points (bps):
106+
- 1 bps = 0.01%
107+
- 100 bps = 1%
108+
- 10000 bps = 100%
137109

138-
All contract updates are serialized through `TxManager` to prevent nonce conflicts:
110+
On-chain prices are only updated when price change exceeds the threshold, avoiding unnecessary Gas costs.
139111

140-
- Holds a mutex to ensure only one transaction is sent at a time
141-
- Manages nonce retrieval and transaction confirmation
142-
- Used by both `BaseFeeUpdater` and `ScalarUpdater`
112+
## Monitoring
143113

144-
### Base Fee Updater
114+
### Prometheus Metrics
145115

146-
- Runs on a fixed interval (default 6s)
147-
- Fetches L1 base fee and blob base fee
148-
- Updates L2 contract when threshold is exceeded
116+
When metrics server is enabled, access `http://<host>:<port>/metrics`:
149117

150-
### Scalar Updater
118+
| Metric | Type | Description |
119+
|--------|------|-------------|
120+
| `last_successful_update_timestamp` | Gauge | Last successful update timestamp |
121+
| `updates_total{type="updated"}` | Counter | Actual update count |
122+
| `updates_total{type="skipped"}` | Counter | Skipped update count |
123+
| `update_errors_total{type="price"}` | Counter | Update error count |
124+
| `account_balance_eth` | Gauge | Oracle account balance |
151125

152-
- Runs every N base fee update cycles (default 10)
153-
- Reads `CommitBatch` events from L1 Rollup
154-
- Calculates commit and blob scalars
155-
- Updates L2 contract when necessary
126+
### Health Check
156127

157-
### Blob Processing
128+
```bash
129+
curl http://<host>:<port>/health
130+
```
158131

159-
Blob data processing is partially implemented (interface defined in `calc/blob.go`). The actual blob parsing and L2 transaction extraction is deferred for future implementation.
132+
### Suggested Alert Rules
133+
134+
```yaml
135+
# Price not updated for a long time
136+
- alert: TokenPriceOracleStalled
137+
expr: time() - last_successful_update_timestamp > 300
138+
for: 1m
139+
labels:
140+
severity: critical
141+
142+
# Low account balance
143+
- alert: TokenPriceOracleLowBalance
144+
expr: account_balance_eth < 0.1
145+
for: 5m
146+
labels:
147+
severity: warning
148+
```
149+
150+
## Project Structure
160151
161-
## Testing
152+
```
153+
token-price-oracle/
154+
├── cmd/ # Entry point
155+
├── flags/ # CLI flags definition
156+
├── config/ # Configuration loading
157+
├── client/ # Client wrappers
158+
│ ├── l2_client.go # L2 chain client
159+
│ ├── price_feed.go # Price feed interface
160+
│ ├── bitget_sdk.go # Bitget API client
161+
│ └── sign.go # External signing
162+
├── updater/ # Update logic
163+
│ ├── token_price.go # Price updater
164+
│ ├── tx_manager.go # Transaction manager
165+
│ └── factory.go # Factory methods
166+
├── metrics/ # Prometheus metrics
167+
└── README.md # This document
168+
```
169+
170+
## Development
162171

163172
```bash
164-
# Run all tests
165-
go test ./...
173+
# Run tests
174+
make test
166175

167176
# Test Bitget price feed (requires network)
168177
go test ./client -run TestBitgetPriceFeed -v
169178

170-
# Skip integration tests
171-
go test ./... -short
179+
# Format code
180+
go fmt ./...
181+
182+
# Local run
183+
cp env.example .env
184+
# Edit .env configuration
185+
source .env && make run
172186
```
173187

188+
## License
189+
190+
MIT

0 commit comments

Comments
 (0)