diff --git a/.github/workflows/token-price-oracle.yml b/.github/workflows/token-price-oracle.yml new file mode 100644 index 000000000..f84e1aafd --- /dev/null +++ b/.github/workflows/token-price-oracle.yml @@ -0,0 +1,36 @@ +name: Token-price-oracle + +on: + push: + branches: + - main + paths: + - "token-price-oracle/**" + - ".github/workflows/token-price-oracle.yml" + pull_request: + paths: + - "token-price-oracle/**" + - ".github/workflows/token-price-oracle.yml" + +permissions: + contents: read + +defaults: + run: + working-directory: "token-price-oracle" + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: 1.24.x + - name: Run build + run: make build + - name: Run tests + run: make test diff --git a/token-price-oracle/updater/token_price.go b/token-price-oracle/updater/token_price.go index a4fce38e0..fe185ce3c 100644 --- a/token-price-oracle/updater/token_price.go +++ b/token-price-oracle/updater/token_price.go @@ -356,10 +356,15 @@ func (u *PriceUpdater) calculatePriceRatioWithInfo(tokenID uint16, tokenPrice *c priceRatio.Mul(priceRatio, tokenScaleFloat) // Step 3: Multiply by 10^(18 - tokenDecimals) - // ETH has 18 decimals, so we need to adjust for token decimals - decimalAdjustment := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(18-tokenDecimals)), nil) - decimalAdjustmentFloat := new(big.Float).SetInt(decimalAdjustment) - priceRatio.Mul(priceRatio, decimalAdjustmentFloat) + // ETH has 18 decimals, so we need to adjust for token decimals. tokenDecimals + // is uint8, so subtract as int64; big.Int.Exp yields 1 for a negative exponent, + // so tokens with more than 18 decimals divide by 10^(tokenDecimals-18) instead. + decimalExponent := int64(18) - int64(tokenDecimals) + if decimalExponent < 0 { + priceRatio.Quo(priceRatio, new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(-decimalExponent), nil))) + } else { + priceRatio.Mul(priceRatio, new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(decimalExponent), nil))) + } // Step 4: Finally divide by ethPriceUSD priceRatio.Quo(priceRatio, tokenPrice.EthPriceUSD) diff --git a/token-price-oracle/updater/token_price_test.go b/token-price-oracle/updater/token_price_test.go new file mode 100644 index 000000000..e55250d02 --- /dev/null +++ b/token-price-oracle/updater/token_price_test.go @@ -0,0 +1,34 @@ +package updater + +import ( + "math/big" + "testing" + + "morph-l2/token-price-oracle/client" +) + +func TestCalculatePriceRatioScalesDownDecimalsAbove18(t *testing.T) { + updater := &PriceUpdater{} + price := &client.TokenPrice{ + TokenID: 1, + Symbol: "TOKEN24", + TokenPriceUSD: big.NewFloat(1), + EthPriceUSD: big.NewFloat(0.5), + } + info := &TokenInfo{ + Decimals: 24, + Scale: big.NewInt(1_000_000), + IsActive: true, + } + + got, err := updater.calculatePriceRatioWithInfo(1, price, info) + if err != nil { + t.Fatal(err) + } + + // 1e6 * (1 USD / 0.5 USD per ETH) * 1e(18-24) = 2. + // A uint8 subtraction would wrap to 250 and scale by 1e250 instead. + if got.Cmp(big.NewInt(2)) != 0 { + t.Fatalf("price ratio = %s, want 2", got) + } +}