From a2c584a99704be27cafecd638b9a7c5b33be4bd0 Mon Sep 17 00:00:00 2001 From: corey Date: Wed, 9 Sep 2026 11:05:33 +0800 Subject: [PATCH 1/6] fix: reject unsupported fee token decimals Co-authored-by: Cursor --- .../contracts/l2/system/IL2TokenRegistry.sol | 1 + .../contracts/l2/system/L2TokenRegistry.sol | 3 ++ .../contracts/test/L2TokenRegistry.t.sol | 18 +++++++++++ token-price-oracle/updater/token_price.go | 7 +++- .../updater/token_price_test.go | 32 +++++++++++++++++++ 5 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 token-price-oracle/updater/token_price_test.go diff --git a/contracts/contracts/l2/system/IL2TokenRegistry.sol b/contracts/contracts/l2/system/IL2TokenRegistry.sol index 38db77a4e..98a34b8cf 100644 --- a/contracts/contracts/l2/system/IL2TokenRegistry.sol +++ b/contracts/contracts/l2/system/IL2TokenRegistry.sol @@ -70,6 +70,7 @@ interface IL2TokenRegistry { error InvalidArrayLength(); error DifferentLength(); error ZeroTokenAmount(); + error UnsupportedTokenDecimals(); /*////////////////////////////////////////////////////////////// Allow List Functions diff --git a/contracts/contracts/l2/system/L2TokenRegistry.sol b/contracts/contracts/l2/system/L2TokenRegistry.sol index 3ea5ac4b1..a9c67c907 100644 --- a/contracts/contracts/l2/system/L2TokenRegistry.sol +++ b/contracts/contracts/l2/system/L2TokenRegistry.sol @@ -234,6 +234,7 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar } catch { // If call fails, use default value 18 } + if (decimals > 18) revert UnsupportedTokenDecimals(); // Register token (isActive defaults to false) // Note: balanceSlot is stored as actualSlot + 1 if needBalanceSlot is true, otherwise 0 @@ -286,6 +287,8 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar } catch { // If call fails, use default value 18 } + if (decimals > 18) revert UnsupportedTokenDecimals(); + // Update registration information // Note: balanceSlot is stored as actualSlot + 1 if needBalanceSlot is true, otherwise 0 address oldAddress = tokenRegistry[_tokenID].tokenAddress; diff --git a/contracts/contracts/test/L2TokenRegistry.t.sol b/contracts/contracts/test/L2TokenRegistry.t.sol index ddefe5165..5db80a013 100644 --- a/contracts/contracts/test/L2TokenRegistry.t.sol +++ b/contracts/contracts/test/L2TokenRegistry.t.sol @@ -136,6 +136,14 @@ contract L2TokenRegistryTest is Test { assertEq(info.decimals, 18); // DAI has 18 decimals } + function test_registerToken_reverts_when_decimals_exceed_18() public { + MockERC20 token24 = new MockERC20("24 Decimal Token", "TOKEN24", 24); + + vm.expectRevert(IL2TokenRegistry.UnsupportedTokenDecimals.selector); + vm.prank(owner); + priceOracle.registerToken(4, address(token24), bytes32(0), false, 1e18); + } + function test_registerToken_setsIsActiveToFalse() public { vm.prank(owner); priceOracle.registerToken(TOKEN_ID_USDC, address(usdc), BALANCE_SLOT_USDC, true, SCALE_USDC); @@ -414,6 +422,16 @@ contract L2TokenRegistryTest is Test { assertEq(info.decimals, 18); // Should fetch DAI's decimals } + function test_updateTokenInfo_reverts_when_decimals_exceed_18() public { + vm.prank(owner); + priceOracle.registerToken(TOKEN_ID_USDC, address(usdc), BALANCE_SLOT_USDC, true, SCALE_USDC); + + MockERC20 token24 = new MockERC20("24 Decimal Token", "TOKEN24", 24); + vm.expectRevert(IL2TokenRegistry.UnsupportedTokenDecimals.selector); + vm.prank(owner); + priceOracle.updateTokenInfo(TOKEN_ID_USDC, address(token24), BALANCE_SLOT_USDC, true, true, SCALE_USDC); + } + function test_updateTokenInfo_reverts_when_scale_is_zero() public { // First register a token vm.prank(owner); diff --git a/token-price-oracle/updater/token_price.go b/token-price-oracle/updater/token_price.go index a4fce38e0..194112361 100644 --- a/token-price-oracle/updater/token_price.go +++ b/token-price-oracle/updater/token_price.go @@ -338,6 +338,10 @@ func (u *PriceUpdater) calculatePriceRatioWithInfo(tokenID uint16, tokenPrice *c tokenScale := tokenInfo.Scale tokenDecimals := tokenInfo.Decimals + if tokenDecimals > 18 { + return nil, fmt.Errorf("unsupported decimals %d for token %d: ETH has 18 decimals", tokenDecimals, tokenID) + } + // Check ETH price is not zero if tokenPrice.EthPriceUSD.Cmp(big.NewFloat(0)) == 0 { return nil, fmt.Errorf("ETH price is zero") @@ -357,7 +361,8 @@ func (u *PriceUpdater) calculatePriceRatioWithInfo(tokenID uint16, tokenPrice *c // 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) + decimalExponent := int64(18) - int64(tokenDecimals) + decimalAdjustment := new(big.Int).Exp(big.NewInt(10), big.NewInt(decimalExponent), nil) decimalAdjustmentFloat := new(big.Float).SetInt(decimalAdjustment) priceRatio.Mul(priceRatio, decimalAdjustmentFloat) 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..b1c66495c --- /dev/null +++ b/token-price-oracle/updater/token_price_test.go @@ -0,0 +1,32 @@ +package updater + +import ( + "math/big" + "strings" + "testing" + + "morph-l2/token-price-oracle/client" +) + +func TestCalculatePriceRatioRejectsDecimalsAboveETH(t *testing.T) { + updater := &PriceUpdater{} + price := &client.TokenPrice{ + TokenID: 1, + Symbol: "TOKEN24", + TokenPriceUSD: big.NewFloat(1), + EthPriceUSD: big.NewFloat(2_000), + } + info := &TokenInfo{ + Decimals: 24, + Scale: big.NewInt(1_000_000), + IsActive: true, + } + + _, err := updater.calculatePriceRatioWithInfo(1, price, info) + if err == nil { + t.Fatal("expected decimals above 18 to be rejected") + } + if !strings.Contains(err.Error(), "unsupported decimals 24") { + t.Fatalf("unexpected error: %v", err) + } +} From 5e37a51651e205012f13e9234c605a7500149566 Mon Sep 17 00:00:00 2001 From: corey Date: Wed, 9 Sep 2026 11:12:30 +0800 Subject: [PATCH 2/6] fix: scale fee-token decimals in signed exponent space Keep L2TokenRegistry registration unrestricted. The overflow is in the oracle exponent, so apply 10^(18-decimals) with a signed integer and divide when decimals exceed 18. Co-authored-by: Cursor --- .../contracts/l2/system/IL2TokenRegistry.sol | 1 - .../contracts/l2/system/L2TokenRegistry.sol | 3 -- .../contracts/test/L2TokenRegistry.t.sol | 18 ---------- token-price-oracle/updater/token_price.go | 33 +++++++++++++------ .../updater/token_price_test.go | 17 +++++----- 5 files changed, 32 insertions(+), 40 deletions(-) diff --git a/contracts/contracts/l2/system/IL2TokenRegistry.sol b/contracts/contracts/l2/system/IL2TokenRegistry.sol index 98a34b8cf..38db77a4e 100644 --- a/contracts/contracts/l2/system/IL2TokenRegistry.sol +++ b/contracts/contracts/l2/system/IL2TokenRegistry.sol @@ -70,7 +70,6 @@ interface IL2TokenRegistry { error InvalidArrayLength(); error DifferentLength(); error ZeroTokenAmount(); - error UnsupportedTokenDecimals(); /*////////////////////////////////////////////////////////////// Allow List Functions diff --git a/contracts/contracts/l2/system/L2TokenRegistry.sol b/contracts/contracts/l2/system/L2TokenRegistry.sol index a9c67c907..3ea5ac4b1 100644 --- a/contracts/contracts/l2/system/L2TokenRegistry.sol +++ b/contracts/contracts/l2/system/L2TokenRegistry.sol @@ -234,7 +234,6 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar } catch { // If call fails, use default value 18 } - if (decimals > 18) revert UnsupportedTokenDecimals(); // Register token (isActive defaults to false) // Note: balanceSlot is stored as actualSlot + 1 if needBalanceSlot is true, otherwise 0 @@ -287,8 +286,6 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar } catch { // If call fails, use default value 18 } - if (decimals > 18) revert UnsupportedTokenDecimals(); - // Update registration information // Note: balanceSlot is stored as actualSlot + 1 if needBalanceSlot is true, otherwise 0 address oldAddress = tokenRegistry[_tokenID].tokenAddress; diff --git a/contracts/contracts/test/L2TokenRegistry.t.sol b/contracts/contracts/test/L2TokenRegistry.t.sol index 5db80a013..ddefe5165 100644 --- a/contracts/contracts/test/L2TokenRegistry.t.sol +++ b/contracts/contracts/test/L2TokenRegistry.t.sol @@ -136,14 +136,6 @@ contract L2TokenRegistryTest is Test { assertEq(info.decimals, 18); // DAI has 18 decimals } - function test_registerToken_reverts_when_decimals_exceed_18() public { - MockERC20 token24 = new MockERC20("24 Decimal Token", "TOKEN24", 24); - - vm.expectRevert(IL2TokenRegistry.UnsupportedTokenDecimals.selector); - vm.prank(owner); - priceOracle.registerToken(4, address(token24), bytes32(0), false, 1e18); - } - function test_registerToken_setsIsActiveToFalse() public { vm.prank(owner); priceOracle.registerToken(TOKEN_ID_USDC, address(usdc), BALANCE_SLOT_USDC, true, SCALE_USDC); @@ -422,16 +414,6 @@ contract L2TokenRegistryTest is Test { assertEq(info.decimals, 18); // Should fetch DAI's decimals } - function test_updateTokenInfo_reverts_when_decimals_exceed_18() public { - vm.prank(owner); - priceOracle.registerToken(TOKEN_ID_USDC, address(usdc), BALANCE_SLOT_USDC, true, SCALE_USDC); - - MockERC20 token24 = new MockERC20("24 Decimal Token", "TOKEN24", 24); - vm.expectRevert(IL2TokenRegistry.UnsupportedTokenDecimals.selector); - vm.prank(owner); - priceOracle.updateTokenInfo(TOKEN_ID_USDC, address(token24), BALANCE_SLOT_USDC, true, true, SCALE_USDC); - } - function test_updateTokenInfo_reverts_when_scale_is_zero() public { // First register a token vm.prank(owner); diff --git a/token-price-oracle/updater/token_price.go b/token-price-oracle/updater/token_price.go index 194112361..6609ae1e0 100644 --- a/token-price-oracle/updater/token_price.go +++ b/token-price-oracle/updater/token_price.go @@ -338,10 +338,6 @@ func (u *PriceUpdater) calculatePriceRatioWithInfo(tokenID uint16, tokenPrice *c tokenScale := tokenInfo.Scale tokenDecimals := tokenInfo.Decimals - if tokenDecimals > 18 { - return nil, fmt.Errorf("unsupported decimals %d for token %d: ETH has 18 decimals", tokenDecimals, tokenID) - } - // Check ETH price is not zero if tokenPrice.EthPriceUSD.Cmp(big.NewFloat(0)) == 0 { return nil, fmt.Errorf("ETH price is zero") @@ -359,12 +355,10 @@ func (u *PriceUpdater) calculatePriceRatioWithInfo(tokenID uint16, tokenPrice *c tokenScaleFloat := new(big.Float).SetInt(tokenScale) priceRatio.Mul(priceRatio, tokenScaleFloat) - // Step 3: Multiply by 10^(18 - tokenDecimals) - // ETH has 18 decimals, so we need to adjust for token decimals - decimalExponent := int64(18) - int64(tokenDecimals) - decimalAdjustment := new(big.Int).Exp(big.NewInt(10), big.NewInt(decimalExponent), nil) - decimalAdjustmentFloat := new(big.Float).SetInt(decimalAdjustment) - priceRatio.Mul(priceRatio, decimalAdjustmentFloat) + // Step 3: Scale by 10^(18 - tokenDecimals) in signed integer space. + // tokenDecimals is uint8; `18-tokenDecimals` would wrap (24 → 250). + // Tokens with more than 18 decimals divide instead of multiply. + applyNativeDecimalAdjustment(priceRatio, tokenDecimals) // Step 4: Finally divide by ethPriceUSD priceRatio.Quo(priceRatio, tokenPrice.EthPriceUSD) @@ -392,6 +386,25 @@ func (u *PriceUpdater) calculatePriceRatioWithInfo(tokenID uint16, tokenPrice *c return priceRatioInt, nil } +// applyNativeDecimalAdjustment multiplies ratio by 10^(18-decimals). +// When decimals > 18 the exponent is negative, so this divides instead. +func applyNativeDecimalAdjustment(priceRatio *big.Float, tokenDecimals uint8) { + exponent := int64(18) - int64(tokenDecimals) + adjustment := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(absInt64(exponent)), nil)) + if exponent >= 0 { + priceRatio.Mul(priceRatio, adjustment) + return + } + priceRatio.Quo(priceRatio, adjustment) +} + +func absInt64(v int64) int64 { + if v < 0 { + return -v + } + return v +} + // updateBalanceMetrics queries and updates balance metrics func (u *PriceUpdater) updateBalanceMetrics(ctx context.Context) error { // Get account address diff --git a/token-price-oracle/updater/token_price_test.go b/token-price-oracle/updater/token_price_test.go index b1c66495c..71598e9fd 100644 --- a/token-price-oracle/updater/token_price_test.go +++ b/token-price-oracle/updater/token_price_test.go @@ -2,19 +2,18 @@ package updater import ( "math/big" - "strings" "testing" "morph-l2/token-price-oracle/client" ) -func TestCalculatePriceRatioRejectsDecimalsAboveETH(t *testing.T) { +func TestCalculatePriceRatioScalesDecimalsAboveETH(t *testing.T) { updater := &PriceUpdater{} price := &client.TokenPrice{ TokenID: 1, Symbol: "TOKEN24", TokenPriceUSD: big.NewFloat(1), - EthPriceUSD: big.NewFloat(2_000), + EthPriceUSD: big.NewFloat(0.5), } info := &TokenInfo{ Decimals: 24, @@ -22,11 +21,13 @@ func TestCalculatePriceRatioRejectsDecimalsAboveETH(t *testing.T) { IsActive: true, } - _, err := updater.calculatePriceRatioWithInfo(1, price, info) - if err == nil { - t.Fatal("expected decimals above 18 to be rejected") + got, err := updater.calculatePriceRatioWithInfo(1, price, info) + if err != nil { + t.Fatal(err) } - if !strings.Contains(err.Error(), "unsupported decimals 24") { - t.Fatalf("unexpected error: %v", err) + + // 1e6 * (1 / 0.5) * 10^(18-24) = 2. Must not wrap 18-24 as uint8 250. + if got.Cmp(big.NewInt(2)) != 0 { + t.Fatalf("price ratio = %s, want 2", got) } } From 17c8bb487544016436dc4948ea09853d41b5c386 Mon Sep 17 00:00:00 2001 From: corey Date: Wed, 9 Sep 2026 11:17:34 +0800 Subject: [PATCH 3/6] fix: subtract token decimals as int64 in price ratio Co-authored-by: Cursor --- token-price-oracle/updater/token_price.go | 28 ++++--------------- .../updater/token_price_test.go | 8 +++--- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/token-price-oracle/updater/token_price.go b/token-price-oracle/updater/token_price.go index 6609ae1e0..014f58c01 100644 --- a/token-price-oracle/updater/token_price.go +++ b/token-price-oracle/updater/token_price.go @@ -355,10 +355,11 @@ func (u *PriceUpdater) calculatePriceRatioWithInfo(tokenID uint16, tokenPrice *c tokenScaleFloat := new(big.Float).SetInt(tokenScale) priceRatio.Mul(priceRatio, tokenScaleFloat) - // Step 3: Scale by 10^(18 - tokenDecimals) in signed integer space. - // tokenDecimals is uint8; `18-tokenDecimals` would wrap (24 → 250). - // Tokens with more than 18 decimals divide instead of multiply. - applyNativeDecimalAdjustment(priceRatio, tokenDecimals) + // 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)-int64(tokenDecimals)), nil) + decimalAdjustmentFloat := new(big.Float).SetInt(decimalAdjustment) + priceRatio.Mul(priceRatio, decimalAdjustmentFloat) // Step 4: Finally divide by ethPriceUSD priceRatio.Quo(priceRatio, tokenPrice.EthPriceUSD) @@ -386,25 +387,6 @@ func (u *PriceUpdater) calculatePriceRatioWithInfo(tokenID uint16, tokenPrice *c return priceRatioInt, nil } -// applyNativeDecimalAdjustment multiplies ratio by 10^(18-decimals). -// When decimals > 18 the exponent is negative, so this divides instead. -func applyNativeDecimalAdjustment(priceRatio *big.Float, tokenDecimals uint8) { - exponent := int64(18) - int64(tokenDecimals) - adjustment := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(absInt64(exponent)), nil)) - if exponent >= 0 { - priceRatio.Mul(priceRatio, adjustment) - return - } - priceRatio.Quo(priceRatio, adjustment) -} - -func absInt64(v int64) int64 { - if v < 0 { - return -v - } - return v -} - // updateBalanceMetrics queries and updates balance metrics func (u *PriceUpdater) updateBalanceMetrics(ctx context.Context) error { // Get account address diff --git a/token-price-oracle/updater/token_price_test.go b/token-price-oracle/updater/token_price_test.go index 71598e9fd..cc8ce77eb 100644 --- a/token-price-oracle/updater/token_price_test.go +++ b/token-price-oracle/updater/token_price_test.go @@ -7,7 +7,7 @@ import ( "morph-l2/token-price-oracle/client" ) -func TestCalculatePriceRatioScalesDecimalsAboveETH(t *testing.T) { +func TestCalculatePriceRatioDoesNotWrapDecimalsAbove18(t *testing.T) { updater := &PriceUpdater{} price := &client.TokenPrice{ TokenID: 1, @@ -26,8 +26,8 @@ func TestCalculatePriceRatioScalesDecimalsAboveETH(t *testing.T) { t.Fatal(err) } - // 1e6 * (1 / 0.5) * 10^(18-24) = 2. Must not wrap 18-24 as uint8 250. - if got.Cmp(big.NewInt(2)) != 0 { - t.Fatalf("price ratio = %s, want 2", got) + // 18-tokenDecimals as uint8 wraps to 250, which would scale by 1e250. + if got.Cmp(new(big.Int).Exp(big.NewInt(10), big.NewInt(30), nil)) >= 0 { + t.Fatalf("price ratio %s looks like a wrapped 1e250 exponent", got) } } From 6f96bd005fd9b06eeeeae6172ab291d423a18713 Mon Sep 17 00:00:00 2001 From: corey Date: Wed, 9 Sep 2026 11:36:00 +0800 Subject: [PATCH 4/6] fix: divide price ratio when token decimals exceed 18 Co-authored-by: Cursor --- token-price-oracle/updater/token_price.go | 13 +++++++++---- token-price-oracle/updater/token_price_test.go | 9 +++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/token-price-oracle/updater/token_price.go b/token-price-oracle/updater/token_price.go index 014f58c01..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)-int64(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 index cc8ce77eb..e55250d02 100644 --- a/token-price-oracle/updater/token_price_test.go +++ b/token-price-oracle/updater/token_price_test.go @@ -7,7 +7,7 @@ import ( "morph-l2/token-price-oracle/client" ) -func TestCalculatePriceRatioDoesNotWrapDecimalsAbove18(t *testing.T) { +func TestCalculatePriceRatioScalesDownDecimalsAbove18(t *testing.T) { updater := &PriceUpdater{} price := &client.TokenPrice{ TokenID: 1, @@ -26,8 +26,9 @@ func TestCalculatePriceRatioDoesNotWrapDecimalsAbove18(t *testing.T) { t.Fatal(err) } - // 18-tokenDecimals as uint8 wraps to 250, which would scale by 1e250. - if got.Cmp(new(big.Int).Exp(big.NewInt(10), big.NewInt(30), nil)) >= 0 { - t.Fatalf("price ratio %s looks like a wrapped 1e250 exponent", got) + // 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) } } From 064c7d7969cec548dd9b23d35d12baf125959510 Mon Sep 17 00:00:00 2001 From: corey Date: Wed, 9 Sep 2026 12:07:04 +0800 Subject: [PATCH 5/6] ci: run token-price-oracle build and tests in GitHub Actions The module had a Makefile test target but no workflow, so the decimals regression would not have been caught by CI. Co-authored-by: Cursor --- .github/workflows/token-price-oracle.yml | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/token-price-oracle.yml diff --git a/.github/workflows/token-price-oracle.yml b/.github/workflows/token-price-oracle.yml new file mode 100644 index 000000000..addac48bd --- /dev/null +++ b/.github/workflows/token-price-oracle.yml @@ -0,0 +1,34 @@ +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@v3 + - 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 From ae7cbdc8468c92a2457bd6ff8d9f23a03e1c3d28 Mon Sep 17 00:00:00 2001 From: corey Date: Fri, 11 Sep 2026 10:05:36 +0800 Subject: [PATCH 6/6] ci: upgrade token-price-oracle checkout to v4 Use a supported Node 20 checkout action and disable credential persistence for PR-controlled build/test jobs. Co-authored-by: Cursor --- .github/workflows/token-price-oracle.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/token-price-oracle.yml b/.github/workflows/token-price-oracle.yml index addac48bd..f84e1aafd 100644 --- a/.github/workflows/token-price-oracle.yml +++ b/.github/workflows/token-price-oracle.yml @@ -23,7 +23,9 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + with: + persist-credentials: false - name: Install Go uses: actions/setup-go@v5 with: