Skip to content

Commit

Permalink
Add kroma support (#11179)
Browse files Browse the repository at this point in the history
* Add kroma support

* Bump ctf for kroma client support

* add kroma l1 gas test
  • Loading branch information
HelloKashif authored Nov 6, 2023
1 parent a757268 commit bda4d5a
Show file tree
Hide file tree
Showing 14 changed files with 263 additions and 15 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/on-demand-ocr-soak-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ on:
- "LINEA_MAINNET"
- "FANTOM_TESTNET"
- "FANTOM_MAINNET"
- "KROMA_MAINNET"
- "KROMA_SEPOLIA"
fundingPrivateKey:
description: Private funding key (Skip for Simulated)
required: false
Expand Down
26 changes: 26 additions & 0 deletions core/chains/evm/config/toml/defaults/Kroma_Mainnet.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
ChainID = '255'
ChainType = 'kroma' # Kroma is based on the Optimism Bedrock architechture
FinalityDepth = 400
LogPollInterval = '2s'
NoNewHeadsThreshold = '40s'
MinIncomingConfirmations = 1

[GasEstimator]
EIP1559DynamicFees = true
PriceMin = '1 wei'
BumpMin = '100 wei'

[GasEstimator.BlockHistory]
BlockHistorySize = 24

[Transactions]
ResendAfterThreshold = '30s'

[HeadTracker]
HistoryDepth = 400

[NodePool]
SyncThreshold = 10

[OCR]
ContractConfirmations = 1
26 changes: 26 additions & 0 deletions core/chains/evm/config/toml/defaults/Kroma_Sepolia.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
ChainID = '2358'
ChainType = 'kroma' # Kroma is based on the Optimism Bedrock architechture
FinalityDepth = 400
LogPollInterval = '2s'
NoNewHeadsThreshold = '40s'
MinIncomingConfirmations = 1

[GasEstimator]
EIP1559DynamicFees = true
PriceMin = '1 wei'
BumpMin = '100 wei'

[GasEstimator.BlockHistory]
BlockHistorySize = 24

[Transactions]
ResendAfterThreshold = '30s'

[HeadTracker]
HistoryDepth = 400

[NodePool]
SyncThreshold = 10

[OCR]
ContractConfirmations = 1
2 changes: 1 addition & 1 deletion core/chains/evm/gas/chain_specific.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func chainSpecificIsUsable(tx evmtypes.Transaction, baseFee *assets.Wei, chainTy
return false
}
}
if chainType == config.ChainOptimismBedrock {
if chainType == config.ChainOptimismBedrock || chainType == config.ChainKroma {
// This is a special deposit transaction type introduced in Bedrock upgrade.
// This is a system transaction that it will occur at least one time per block.
// We should discard this type before even processing it to avoid flooding the
Expand Down
12 changes: 11 additions & 1 deletion core/chains/evm/gas/rollups/l1_gas_price_oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,18 @@ const (
// `function l1BaseFee() external view returns (uint256);`
OPGasOracle_l1BaseFee = "519b4bd3"

// GasOracleAddress is the address of the precompiled contract that exists on Kroma chain.
// This is the case for Kroma.
KromaGasOracleAddress = "0x4200000000000000000000000000000000000005"
// GasOracle_l1BaseFee is the a hex encoded call to:
// `function l1BaseFee() external view returns (uint256);`
KromaGasOracle_l1BaseFee = "519b4bd3"

// Interval at which to poll for L1BaseFee. A good starting point is the L1 block time.
PollPeriod = 12 * time.Second
)

var supportedChainTypes = []config.ChainType{config.ChainArbitrum, config.ChainOptimismBedrock}
var supportedChainTypes = []config.ChainType{config.ChainArbitrum, config.ChainOptimismBedrock, config.ChainKroma}

func IsRollupWithL1Support(chainType config.ChainType) bool {
return slices.Contains(supportedChainTypes, chainType)
Expand All @@ -76,6 +83,9 @@ func NewL1GasPriceOracle(lggr logger.Logger, ethClient ethClient, chainType conf
case config.ChainOptimismBedrock:
address = OPGasOracleAddress
callArgs = OPGasOracle_l1BaseFee
case config.ChainKroma:
address = KromaGasOracleAddress
callArgs = KromaGasOracle_l1BaseFee
default:
panic(fmt.Sprintf("Received unspported chaintype %s", chainType))
}
Expand Down
22 changes: 22 additions & 0 deletions core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,28 @@ func TestL1GasPriceOracle(t *testing.T) {
assert.Equal(t, assets.NewWei(l1BaseFee), gasPrice)
})

t.Run("Calling GasPrice on started Kroma L1Oracle returns Kroma l1GasPrice", func(t *testing.T) {
l1BaseFee := big.NewInt(200)

ethClient := mocks.NewETHClient(t)
ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) {
callMsg := args.Get(1).(ethereum.CallMsg)
blockNumber := args.Get(2).(*big.Int)
assert.Equal(t, KromaGasOracleAddress, callMsg.To.String())
assert.Equal(t, KromaGasOracle_l1BaseFee, fmt.Sprintf("%x", callMsg.Data))
assert.Nil(t, blockNumber)
}).Return(common.BigToHash(l1BaseFee).Bytes(), nil)

oracle := NewL1GasPriceOracle(logger.TestLogger(t), ethClient, config.ChainKroma)
require.NoError(t, oracle.Start(testutils.Context(t)))
t.Cleanup(func() { assert.NoError(t, oracle.Close()) })

gasPrice, err := oracle.GasPrice(testutils.Context(t))
require.NoError(t, err)

assert.Equal(t, assets.NewWei(l1BaseFee), gasPrice)
})

t.Run("Calling GasPrice on started OPStack L1Oracle returns OPStack l1GasPrice", func(t *testing.T) {
l1BaseFee := big.NewInt(200)

Expand Down
4 changes: 3 additions & 1 deletion core/config/chaintype.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,18 @@ const (
ChainOptimismBedrock ChainType = "optimismBedrock"
ChainXDai ChainType = "xdai"
ChainCelo ChainType = "celo"
ChainKroma ChainType = "kroma"
)

var ErrInvalidChainType = fmt.Errorf("must be one of %s or omitted", strings.Join([]string{
string(ChainArbitrum), string(ChainMetis), string(ChainXDai), string(ChainOptimismBedrock), string(ChainCelo),
string(ChainKroma),
}, ", "))

// IsValid returns true if the ChainType value is known or empty.
func (c ChainType) IsValid() bool {
switch c {
case "", ChainArbitrum, ChainMetis, ChainOptimismBedrock, ChainXDai, ChainCelo:
case "", ChainArbitrum, ChainMetis, ChainOptimismBedrock, ChainXDai, ChainCelo, ChainKroma:
return true
}
return false
Expand Down
2 changes: 1 addition & 1 deletion core/config/docs/chains-evm.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ BlockBackfillDepth = 10 # Default
# BlockBackfillSkip enables skipping of very long backfills.
BlockBackfillSkip = false # Default
# ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID.
# Available types: arbitrum, metis, optimismBedrock, xdai
# Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma
ChainType = 'arbitrum' # Example
# FinalityDepth is the number of blocks after which an ethereum transaction is considered "final". Note that the default is automatically set based on chain ID so it should not be necessary to change this under normal operation.
# BlocksConsideredFinal determines how deeply we look back to ensure that transactions are confirmed onto the longest chain
Expand Down
4 changes: 2 additions & 2 deletions core/services/chainlink/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1190,7 +1190,7 @@ func TestConfig_Validate(t *testing.T) {
- 1: 6 errors:
- ChainType: invalid value (Foo): must not be set with this chain id
- Nodes: missing: must have at least one node
- ChainType: invalid value (Foo): must be one of arbitrum, metis, xdai, optimismBedrock, celo or omitted
- ChainType: invalid value (Foo): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma or omitted
- HeadTracker.HistoryDepth: invalid value (30): must be equal to or greater than FinalityDepth
- GasEstimator: 2 errors:
- FeeCapDefault: invalid value (101 wei): must be equal to PriceMax (99 wei) since you are using FixedPrice estimation with gas bumping disabled in EIP1559 mode - PriceMax will be used as the FeeCap for transactions instead of FeeCapDefault
Expand All @@ -1199,7 +1199,7 @@ func TestConfig_Validate(t *testing.T) {
- 2: 5 errors:
- ChainType: invalid value (Arbitrum): only "optimismBedrock" can be used with this chain id
- Nodes: missing: must have at least one node
- ChainType: invalid value (Arbitrum): must be one of arbitrum, metis, xdai, optimismBedrock, celo or omitted
- ChainType: invalid value (Arbitrum): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma or omitted
- FinalityDepth: invalid value (0): must be greater than or equal to 1
- MinIncomingConfirmations: invalid value (0): must be greater than or equal to 1
- 3.Nodes: 5 errors:
Expand Down
2 changes: 1 addition & 1 deletion core/services/ocr/contract_tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ func (t *OCRContractTracker) LatestBlockHeight(ctx context.Context) (blockheight
// care about the block height; we have no way of getting the L1 block
// height anyway
return 0, nil
case "", config.ChainArbitrum, config.ChainCelo, config.ChainOptimismBedrock, config.ChainXDai:
case "", config.ChainArbitrum, config.ChainCelo, config.ChainOptimismBedrock, config.ChainXDai, config.ChainKroma:
// continue
}
latestBlockHeight := t.getLatestBlockHeight()
Expand Down
160 changes: 159 additions & 1 deletion docs/CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2907,6 +2907,85 @@ GasLimit = 3800000

</p></details>

<details><summary>Kroma Mainnet (255)</summary><p>

```toml
AutoCreateKey = true
BlockBackfillDepth = 10
BlockBackfillSkip = false
ChainType = 'kroma'
FinalityDepth = 400
FinalityTagEnabled = false
LogBackfillBatchSize = 1000
LogPollInterval = '2s'
LogKeepBlocksDepth = 100000
MinIncomingConfirmations = 1
MinContractPayment = '0.00001 link'
NonceAutoSync = true
NoNewHeadsThreshold = '40s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1

[Transactions]
ForwardersEnabled = false
MaxInFlight = 16
MaxQueued = 250
ReaperInterval = '1h0m0s'
ReaperThreshold = '168h0m0s'
ResendAfterThreshold = '30s'

[BalanceMonitor]
Enabled = true

[GasEstimator]
Mode = 'BlockHistory'
PriceDefault = '20 gwei'
PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether'
PriceMin = '1 wei'
LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
BumpMin = '100 wei'
BumpPercent = 20
BumpThreshold = 3
EIP1559DynamicFees = true
FeeCapDefault = '100 gwei'
TipCapDefault = '1 wei'
TipCapMin = '1 wei'

[GasEstimator.BlockHistory]
BatchSize = 25
BlockHistorySize = 24
CheckInclusionBlocks = 12
CheckInclusionPercentile = 90
TransactionPercentile = 60

[HeadTracker]
HistoryDepth = 400
MaxBufferSize = 3
SamplingInterval = '1s'

[NodePool]
PollFailureThreshold = 5
PollInterval = '10s'
SelectionMode = 'HighestHead'
SyncThreshold = 10
LeaseDuration = '0s'

[OCR]
ContractConfirmations = 1
ContractTransmitterTransmitTimeout = '10s'
DatabaseTimeout = '10s'
ObservationGracePeriod = '1s'

[OCR2]
[OCR2.Automation]
GasLimit = 5300000
```

</p></details>

<details><summary>Optimism Goerli (420)</summary><p>

```toml
Expand Down Expand Up @@ -3301,6 +3380,85 @@ GasLimit = 5300000

</p></details>

<details><summary>Kroma Sepolia (2358)</summary><p>

```toml
AutoCreateKey = true
BlockBackfillDepth = 10
BlockBackfillSkip = false
ChainType = 'kroma'
FinalityDepth = 400
FinalityTagEnabled = false
LogBackfillBatchSize = 1000
LogPollInterval = '2s'
LogKeepBlocksDepth = 100000
MinIncomingConfirmations = 1
MinContractPayment = '0.00001 link'
NonceAutoSync = true
NoNewHeadsThreshold = '40s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1

[Transactions]
ForwardersEnabled = false
MaxInFlight = 16
MaxQueued = 250
ReaperInterval = '1h0m0s'
ReaperThreshold = '168h0m0s'
ResendAfterThreshold = '30s'

[BalanceMonitor]
Enabled = true

[GasEstimator]
Mode = 'BlockHistory'
PriceDefault = '20 gwei'
PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether'
PriceMin = '1 wei'
LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
BumpMin = '100 wei'
BumpPercent = 20
BumpThreshold = 3
EIP1559DynamicFees = true
FeeCapDefault = '100 gwei'
TipCapDefault = '1 wei'
TipCapMin = '1 wei'

[GasEstimator.BlockHistory]
BatchSize = 25
BlockHistorySize = 24
CheckInclusionBlocks = 12
CheckInclusionPercentile = 90
TransactionPercentile = 60

[HeadTracker]
HistoryDepth = 400
MaxBufferSize = 3
SamplingInterval = '1s'

[NodePool]
PollFailureThreshold = 5
PollInterval = '10s'
SelectionMode = 'HighestHead'
SyncThreshold = 10
LeaseDuration = '0s'

[OCR]
ContractConfirmations = 1
ContractTransmitterTransmitTimeout = '10s'
DatabaseTimeout = '10s'
ObservationGracePeriod = '1s'

[OCR2]
[OCR2.Automation]
GasLimit = 5300000
```

</p></details>

<details><summary>Fantom Testnet (4002)</summary><p>

```toml
Expand Down Expand Up @@ -4916,7 +5074,7 @@ BlockBackfillSkip enables skipping of very long backfills.
ChainType = 'arbitrum' # Example
```
ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID.
Available types: arbitrum, metis, optimismBedrock, xdai
Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma

### FinalityDepth
```toml
Expand Down
6 changes: 6 additions & 0 deletions integration-tests/contracts/contract_deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ func NewContractDeployer(bcClient blockchain.EVMClient, logger zerolog.Logger) (
return &LineaContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil
case *blockchain.FantomClient:
return &FantomContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil
case *blockchain.KromaClient:
return &KromaContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil
}
return nil, errors.New("unknown blockchain client implementation for contract deployer, register blockchain client in NewContractDeployer")
}
Expand Down Expand Up @@ -240,6 +242,10 @@ type FantomContractDeployer struct {
*EthereumContractDeployer
}

type KromaContractDeployer struct {
*EthereumContractDeployer
}

// NewEthereumContractDeployer returns an instantiated instance of the ETH contract deployer
func NewEthereumContractDeployer(ethClient blockchain.EVMClient, logger zerolog.Logger) *EthereumContractDeployer {
return &EthereumContractDeployer{
Expand Down
Loading

0 comments on commit bda4d5a

Please sign in to comment.