Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gas-oracle): support gas token volatile exchange rate #1526

Merged
merged 26 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cddd250
feat(gas-oracle): support volatile gas token exchange rate
yiweichi Sep 28, 2024
d57dc24
refactor: gas oracle exchange rate
yiweichi Sep 30, 2024
bef4e0c
clean up
yiweichi Sep 30, 2024
4d6d1f8
chore: auto version bump [bot]
yiweichi Sep 30, 2024
51f5962
revert Cargo.lock
yiweichi Sep 30, 2024
df6442e
fix: lint
yiweichi Oct 7, 2024
6d9fe05
Merge branch 'develop' into feat-gas-oracle-exchange-rate
yiweichi Oct 7, 2024
46ce727
chore: auto version bump [bot]
yiweichi Oct 7, 2024
f39eb8b
fix: lint
yiweichi Oct 7, 2024
9bef845
fix: lint
yiweichi Oct 7, 2024
3900ed8
fix: lint
yiweichi Oct 8, 2024
859195e
fix: lint
yiweichi Oct 8, 2024
02d5272
fix: lint
yiweichi Oct 8, 2024
c5591c6
fix: lint
yiweichi Oct 8, 2024
8179fff
fix: lint
yiweichi Oct 8, 2024
69d5749
fix: lint
yiweichi Oct 8, 2024
39a4a87
remove binance api unit test
yiweichi Oct 8, 2024
19cca3c
rename exchange rate mode
yiweichi Oct 8, 2024
14db0e3
docs: add annotation for token symbol pair
yiweichi Oct 9, 2024
92e2c5f
lint
yiweichi Oct 9, 2024
38ae102
Update rollup/internal/config/relayer.go
yiweichi Oct 9, 2024
93adbea
fix: add validity check for exchangeRate
yiweichi Oct 9, 2024
722f36b
feat: add retry for GetExchangeRateFromBinanceApi and change mode to …
yiweichi Oct 11, 2024
98dcb74
Merge branch 'develop' into feat-gas-oracle-exchange-rate
yiweichi Oct 11, 2024
198fc30
Merge branch 'develop' into feat-gas-oracle-exchange-rate
yiweichi Oct 14, 2024
290c39d
chore: auto version bump [bot]
yiweichi Oct 14, 2024
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 common/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"runtime/debug"
)

var tag = "v4.4.64"
var tag = "v4.4.65"

var commit = func() string {
if info, ok := debug.ReadBuildInfo(); ok {
Expand Down
37 changes: 37 additions & 0 deletions rollup/internal/config/relayer.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,37 @@
package config

import (
"fmt"
"strings"

"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/rpc"
)

const (
FIXED ExchangeRateMode = "Fixed"
BINANCE_API ExchangeRateMode = "BinanceApi"
UNISWAP ExchangeRateMode = "Uniswap"
)

// ExchangeRateMode the mode to retrieve exchange rate
type ExchangeRateMode string

func (m *ExchangeRateMode) UnmarshalText(data []byte) error {
candidates := []string{
string(FIXED),
string(BINANCE_API),
// string(UNISWAP), not supported yet
}
for _, i := range candidates {
if string(data) == i {
*m = ExchangeRateMode(i)
return nil
}
}
return fmt.Errorf("invalid mode: %s, must be one of %s", string(data), strings.Join(candidates, ","))
}

// SenderConfig The config for transaction sender
type SenderConfig struct {
// The RPC endpoint of the ethereum or scroll public node.
Expand Down Expand Up @@ -68,12 +95,22 @@ type RelayerConfig struct {
FinalizeBundleWithoutProofTimeoutSec uint64 `json:"finalize_bundle_without_proof_timeout_sec"`
}

// AlternativeGasTokenConfig The configuration for handling token exchange rates when updating the gas price oracle.
yiweichi marked this conversation as resolved.
Show resolved Hide resolved
type AlternativeGasTokenConfig struct {
Enabled bool `json:"enabled"`
Mode ExchangeRateMode `json:"mode"`
yiweichi marked this conversation as resolved.
Show resolved Hide resolved
FixedExchangeRate float64 `json:"fixed_exchange_rate"` // fixed exchange rate of L2 gas token / L1 gas token
TokenSymbolPair string `json:"token_symbol_pair"` // The pair should be L2 gas token symbol + L1 gas token symbol
}

// GasOracleConfig The config for updating gas price oracle.
type GasOracleConfig struct {
// MinGasPrice store the minimum gas price to set.
MinGasPrice uint64 `json:"min_gas_price"`
// GasPriceDiff is the minimum percentage of gas price difference to update gas oracle.
GasPriceDiff uint64 `json:"gas_price_diff"`
// AlternativeGasTokenConfig The configuration for handling token exchange rates when updating the gas price oracle.
AlternativeGasTokenConfig *AlternativeGasTokenConfig `json:"alternative_gas_token_config"`

// The following configs are only for updating L1 gas price, used for sender in L2.
// The weight for L1 base fee.
Expand Down
27 changes: 27 additions & 0 deletions rollup/internal/controller/relayer/l1_relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
"scroll-tech/common/types"
"scroll-tech/common/utils"

rutils "scroll-tech/rollup/internal/utils"

yiweichi marked this conversation as resolved.
Show resolved Hide resolved
bridgeAbi "scroll-tech/rollup/abi"
"scroll-tech/rollup/internal/config"
"scroll-tech/rollup/internal/controller/sender"
Expand Down Expand Up @@ -151,6 +153,31 @@ func (r *Layer1Relayer) ProcessGasPriceOracle() {
baseFee = block.BaseFee
}

// include the token exchange rate in the fee data if alternative gas token enabled
if r.cfg.GasOracleConfig.AlternativeGasTokenConfig != nil && r.cfg.GasOracleConfig.AlternativeGasTokenConfig.Enabled {
// The exchange rate represent the number of native token on L1 required to exchange for 1 native token on L2.
var exchangeRate float64
switch r.cfg.GasOracleConfig.AlternativeGasTokenConfig.Mode {
case config.FIXED:
exchangeRate = r.cfg.GasOracleConfig.AlternativeGasTokenConfig.FixedExchangeRate
case config.BINANCE_API:
exchangeRate, err = rutils.GetExchangeRateFromBinanceApi(r.cfg.GasOracleConfig.AlternativeGasTokenConfig.TokenSymbolPair)
if err != nil {
log.Error("Failed to get gas token exchange rate from Binance api", "tokenSymbolPair", r.cfg.GasOracleConfig.AlternativeGasTokenConfig.TokenSymbolPair, "err", err)
return
}
default:
log.Error("Invalid alternative gas token mode", "mode", r.cfg.GasOracleConfig.AlternativeGasTokenConfig.Mode)
return
}
if exchangeRate == 0 {
log.Error("Invalid exchange rate", "exchangeRate", exchangeRate)
return
}
baseFee = uint64(math.Ceil(float64(baseFee) / exchangeRate))
colinlyguo marked this conversation as resolved.
Show resolved Hide resolved
yiweichi marked this conversation as resolved.
Show resolved Hide resolved
blobBaseFee = uint64(math.Ceil(float64(blobBaseFee) / exchangeRate))
}

if r.shouldUpdateGasOracle(baseFee, blobBaseFee, isCurie) {
// It indicates the committing batch has been stuck for a long time, it's likely that the L1 gas fee spiked.
// If we are not committing batches due to high fees then we shouldn't update fees to prevent users from paying high l1_data_fee
Expand Down
28 changes: 28 additions & 0 deletions rollup/internal/controller/relayer/l2_relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"math"
"math/big"
"sort"
"strings"
Expand Down Expand Up @@ -324,6 +325,33 @@ func (r *Layer2Relayer) ProcessGasPriceOracle() {
return
}
suggestGasPriceUint64 := uint64(suggestGasPrice.Int64())

// include the token exchange rate in the fee data if alternative gas token enabled
if r.cfg.GasOracleConfig.AlternativeGasTokenConfig != nil && r.cfg.GasOracleConfig.AlternativeGasTokenConfig.Enabled {
// The exchange rate represent the number of native token on L1 required to exchange for 1 native token on L2.
var exchangeRate float64
switch r.cfg.GasOracleConfig.AlternativeGasTokenConfig.Mode {
case config.FIXED:
exchangeRate = r.cfg.GasOracleConfig.AlternativeGasTokenConfig.FixedExchangeRate
case config.BINANCE_API:
exchangeRate, err = rutils.GetExchangeRateFromBinanceApi(r.cfg.GasOracleConfig.AlternativeGasTokenConfig.TokenSymbolPair)
if err != nil {
log.Error("Failed to get gas token exchange rate from Binance api", "tokenSymbolPair", r.cfg.GasOracleConfig.AlternativeGasTokenConfig.TokenSymbolPair, "err", err)
return
}

default:
log.Error("Invalid alternative gas token mode", "mode", r.cfg.GasOracleConfig.AlternativeGasTokenConfig.Mode)
return
}
if exchangeRate == 0 {
log.Error("Invalid exchange rate", "exchangeRate", exchangeRate)
return
}
suggestGasPriceUint64 = uint64(math.Ceil(float64(suggestGasPriceUint64) * exchangeRate))
suggestGasPrice = new(big.Int).SetUint64(suggestGasPriceUint64)
}

expectedDelta := r.lastGasPrice * r.gasPriceDiff / gasPriceDiffPrecision
if r.lastGasPrice > 0 && expectedDelta == 0 {
expectedDelta = 1
Expand Down
57 changes: 57 additions & 0 deletions rollup/internal/utils/exchange_rate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package utils

import (
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"

"github.com/scroll-tech/go-ethereum/log"
)

var BinanceApiEndpoint string = "https://api.binance.com/api/v3/ticker/price?symbol=%s"
colinlyguo marked this conversation as resolved.
Show resolved Hide resolved

type BinanceResponse struct {
Price string `json:"price"`
}

func GetExchangeRateFromBinanceApi(tokenSymbolPair string) (float64, error) {
yiweichi marked this conversation as resolved.
Show resolved Hide resolved
// make HTTP GET request
resp, err := http.Get(fmt.Sprintf(BinanceApiEndpoint, tokenSymbolPair))
if err != nil {
return 0, fmt.Errorf("error making HTTP request: %w", err)
}
defer func() {
err = resp.Body.Close()
if err != nil {
log.Error("error closing response body", "err", err)
}
}()

// check for successful response
if resp.StatusCode != http.StatusOK {
return 0, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}

// read response body
body, err := io.ReadAll(resp.Body)
if err != nil {
return 0, fmt.Errorf("error reading response body: %w", err)
}

// unmarshal JSON response
var data BinanceResponse
err = json.Unmarshal(body, &data)
if err != nil {
return 0, fmt.Errorf("error unmarshaling JSON: %w", err)
}

// convert price string to float64
price, err := strconv.ParseFloat(data.Price, 64)
if err != nil {
return 0, fmt.Errorf("error parsing price string: %w", err)
}

return price, nil
}
Loading