Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f8799a4
poc(cgt): custom gas token l1
hexshire Aug 7, 2025
cdb2efd
poc(cgt): custom gas token l2
hexshire Aug 7, 2025
c8fd3ff
fix: var naming
ashitakah Aug 14, 2025
9da1cef
test: refactor to reuse L1Block repeated tests
0xniha Aug 14, 2025
078832f
fix(cgt): stack too deep (#485)
ashitakah Aug 14, 2025
0353ecb
fix: remove gasPayingToken function in L1Block
0xniha Aug 14, 2025
b23bce5
feat: add fund method to NativeAssetLiquidity
0xniha Aug 15, 2025
0365015
fix(cgt): remove gasPayingToken function from L1Block (#486)
0xniha Aug 15, 2025
cec8a1f
refactor: remove burn method from NativeAssetLiquidity
0xniha Aug 15, 2025
af5f254
refactor(cgt): move cgt flag to portal
hexshire Aug 15, 2025
20b8820
fix: test validation for portal
0xniha Aug 15, 2025
bc6417a
Merge branch 'develop' into chore/cgt-poc-dev-sync-1
hexshire Aug 18, 2025
5f53ccd
chore(cgt): run pre pr
hexshire Aug 18, 2025
a2c9b3a
chore(cgt): consolidate duplicated flags
hexshire Aug 18, 2025
2bc0430
chore(cgt): remove underscore
hexshire Aug 19, 2025
e94f687
Merge branch 'poc/custom-gas-token' of github.com:defi-wonderland/opt…
hexshire Aug 19, 2025
7dec744
fix: cgt flag on depositTransaction test
0xniha Aug 19, 2025
0cfdc41
feat: add cgt flag check in finalizeWithdrawal
0xniha Aug 19, 2025
8ab97c7
refactor: add setIsCustomGasToken internal function
0xniha Aug 19, 2025
f2ed1ec
fix: remove unused using-for directives
0xniha Aug 19, 2025
63c7c4c
feat: add cgt flag check in finalizeWithdrawal (#493)
0xniha Aug 20, 2025
fdd80de
refactor(cgt): add flag setter
hexshire Aug 21, 2025
37a849d
chore(cgt): add withdrawal network type check on fee vaults deploy
0xniha Aug 21, 2025
9d382ea
fix: set withdrawal network as L2 for feevaults when cgt enabled
0xniha Sep 1, 2025
bf8fb20
fix(cgt): set withdrawal network as L2 for feevaults when cgt enabled…
0xniha Sep 1, 2025
7501512
feat(cgt): add deauthorizeMinter to liquidity controller (#506)
0xniha Sep 1, 2025
af44879
chore(cgt): deployer scripts (#508)
0xniha Sep 2, 2025
53e3747
chore: update comment
hexshire Sep 2, 2025
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
20 changes: 12 additions & 8 deletions op-chain-ops/genesis/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,20 +273,24 @@ func (d *GasPriceOracleDeployConfig) OperatorFeeParams() [32]byte {

// GasTokenDeployConfig configures the optional custom gas token functionality.
type GasTokenDeployConfig struct {
// UseCustomGasToken is a flag to indicate that a custom gas token should be used
UseCustomGasToken bool `json:"useCustomGasToken"`
// CustomGasTokenAddress is the address of the ERC20 token to be used to pay for gas on L2.
CustomGasTokenAddress common.Address `json:"customGasTokenAddress"`
// IsCustomGasToken is a flag to indicate that a custom gas token should be used
IsCustomGasToken bool `json:"isCustomGasToken"`
// GasPayingTokenName represents the custom gas token name.
GasPayingTokenName string `json:"gasPayingTokenName"`
// GasPayingTokenSymbol represents the custom gas token symbol.
GasPayingTokenSymbol string `json:"gasPayingTokenSymbol"`
}

var _ ConfigChecker = (*GasTokenDeployConfig)(nil)

func (d *GasTokenDeployConfig) Check(log log.Logger) error {
if d.UseCustomGasToken {
if d.CustomGasTokenAddress == (common.Address{}) {
return fmt.Errorf("%w: CustomGasTokenAddress cannot be address(0)", ErrInvalidDeployConfig)
if d.IsCustomGasToken {
if d.GasPayingTokenName == "" {
return fmt.Errorf("%w: GasPayingTokenName cannot be empty", ErrInvalidDeployConfig)
}
if d.GasPayingTokenSymbol == "" {
return fmt.Errorf("%w: GasPayingTokenSymbol cannot be empty", ErrInvalidDeployConfig)
}
log.Info("Using custom gas token", "address", d.CustomGasTokenAddress)
}
return nil
}
Expand Down
3 changes: 1 addition & 2 deletions op-chain-ops/genesis/testdata/test-deploy-config-full.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"maxSequencerDrift": 20,
"sequencerWindowSize": 100,
"channelTimeout": 30,
"customGasTokenAddress": "0x0000000000000000000000000000000000000000",
"p2pSequencerAddress": "0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc",
"batchInboxAddress": "0x42000000000000000000000000000000000000ff",
"batchSenderAddress": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc",
Expand Down Expand Up @@ -84,7 +83,7 @@
"proofMaturityDelaySeconds": 12,
"disputeGameFinalityDelaySeconds": 6,
"respectedGameType": 0,
"useCustomGasToken": false,
"isCustomGasToken": false,
"useFaultProofs": false,
"useAltDA": false,
"daBondSize": 0,
Expand Down
4 changes: 4 additions & 0 deletions op-chain-ops/interopgen/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ func DeployL2ToL1(l1Host *script.Host, superCfg *SuperchainConfig, superDeployme
AllowCustomDisputeParameters: true,
OperatorFeeScalar: cfg.GasPriceOracleOperatorFeeScalar,
OperatorFeeConstant: cfg.GasPriceOracleOperatorFeeConstant,
IsCustomGasToken: cfg.IsCustomGasToken,
})
if err != nil {
return nil, fmt.Errorf("failed to deploy L2 OP chain: %w", err)
Expand Down Expand Up @@ -324,6 +325,9 @@ func GenesisL2(l2Host *script.Host, cfg *L2Config, deployment *L2Deployment, mul
DeployCrossL2Inbox: multichainDepSet,
EnableGovernance: cfg.EnableGovernance,
FundDevAccounts: cfg.FundDevAccounts,
IsCustomGasToken: cfg.IsCustomGasToken,
GasPayingTokenName: cfg.GasPayingTokenName,
GasPayingTokenSymbol: cfg.GasPayingTokenSymbol,
}); err != nil {
return fmt.Errorf("failed L2 genesis: %w", err)
}
Expand Down
4 changes: 3 additions & 1 deletion op-chain-ops/interopgen/recipe.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,9 @@ func (r *InteropDevL2Recipe) build(l1ChainID uint64, addrs devkeys.Addresses) (*
GasPriceOracleBlobBaseFeeScalar: 810949,
},
GasTokenDeployConfig: genesis.GasTokenDeployConfig{
UseCustomGasToken: false,
IsCustomGasToken: false,
GasPayingTokenName: "Custom Gas Token",
GasPayingTokenSymbol: "CGT",
},
OperatorDeployConfig: genesis.OperatorDeployConfig{
P2PSequencerAddress: sequencerP2P,
Expand Down
5 changes: 5 additions & 0 deletions op-deployer/pkg/deployer/integration_test/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,11 @@ func newChainIntent(t *testing.T, dk *devkeys.MnemonicDevKeys, l1ChainID *big.In
Proposer: addrFor(t, dk, devkeys.ProposerRole.Key(l1ChainID)),
Challenger: addrFor(t, dk, devkeys.ChallengerRole.Key(l1ChainID)),
},
CustomGasToken: &state.CustomGasToken{
Enabled: standard.CustomGasTokenEnabled,
Name: standard.CustomGasTokenName,
Symbol: standard.CustomGasTokenSymbol,
},
}
}

Expand Down
3 changes: 3 additions & 0 deletions op-deployer/pkg/deployer/opcm/l2genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ type L2GenesisInput struct {
DeployCrossL2Inbox bool
EnableGovernance bool
FundDevAccounts bool
IsCustomGasToken bool
GasPayingTokenName string
GasPayingTokenSymbol string
}

type L2GenesisScript script.DeployScriptWithoutOutput[L2GenesisInput]
Expand Down
1 change: 1 addition & 0 deletions op-deployer/pkg/deployer/opcm/opchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type DeployOPChainInput struct {
DisputeClockExtension uint64
DisputeMaxClockDuration uint64
AllowCustomDisputeParameters bool
IsCustomGasToken bool

OperatorFeeScalar uint32
OperatorFeeConstant uint64
Expand Down
9 changes: 9 additions & 0 deletions op-deployer/pkg/deployer/pipeline/l2genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import (
)

type l2GenesisOverrides struct {
IsCustomGasToken bool `json:"isCustomGasToken"`
GasPayingTokenName string `json:"gasPayingTokenName"`
GasPayingTokenSymbol string `json:"gasPayingTokenSymbol"`
FundDevAccounts bool `json:"fundDevAccounts"`
BaseFeeVaultMinimumWithdrawalAmount *hexutil.Big `json:"baseFeeVaultMinimumWithdrawalAmount"`
L1FeeVaultMinimumWithdrawalAmount *hexutil.Big `json:"l1FeeVaultMinimumWithdrawalAmount"`
Expand Down Expand Up @@ -94,6 +97,9 @@ func GenerateL2Genesis(pEnv *Env, intent *state.Intent, bundle ArtifactsBundle,
DeployCrossL2Inbox: len(intent.Chains) > 1,
EnableGovernance: overrides.EnableGovernance,
FundDevAccounts: overrides.FundDevAccounts,
IsCustomGasToken: thisIntent.CustomGasToken.Enabled,
GasPayingTokenName: thisIntent.CustomGasToken.Name,
GasPayingTokenSymbol: thisIntent.CustomGasToken.Symbol,
}); err != nil {
return fmt.Errorf("failed to call L2Genesis script: %w", err)
}
Expand Down Expand Up @@ -156,6 +162,9 @@ func wdNetworkToBig(wd genesis.WithdrawalNetwork) *big.Int {

func defaultOverrides() l2GenesisOverrides {
return l2GenesisOverrides{
IsCustomGasToken: false,
GasPayingTokenName: "Custom Gas Token",
GasPayingTokenSymbol: "CGT",
FundDevAccounts: false,
BaseFeeVaultMinimumWithdrawalAmount: standard.VaultMinWithdrawalAmount,
L1FeeVaultMinimumWithdrawalAmount: standard.VaultMinWithdrawalAmount,
Expand Down
15 changes: 15 additions & 0 deletions op-deployer/pkg/deployer/pipeline/l2genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ func TestCalculateL2GenesisOverrides(t *testing.T) {
SequencerFeeVaultWithdrawalNetwork: "local",
EnableGovernance: false,
GovernanceTokenOwner: standard.GovernanceTokenOwner,
IsCustomGasToken: false,
GasPayingTokenName: "Custom Gas Token",
GasPayingTokenSymbol: "CGT",
},
expectedSchedule: func() *genesis.UpgradeScheduleDeployConfig {
return standard.DefaultHardforkScheduleForTag("")
Expand All @@ -73,6 +76,9 @@ func TestCalculateL2GenesisOverrides(t *testing.T) {
"enableGovernance": true,
"governanceTokenOwner": "0x1111111111111111111111111111111111111111",
"l2GenesisInteropTimeOffset": "0x1234",
"isCustomGasToken": false,
"gasPayingTokenName": "Custom Gas Token",
"gasPayingTokenSymbol": "CGT",
},
},
chainIntent: &state.ChainIntent{},
Expand All @@ -87,6 +93,9 @@ func TestCalculateL2GenesisOverrides(t *testing.T) {
SequencerFeeVaultWithdrawalNetwork: "remote",
EnableGovernance: true,
GovernanceTokenOwner: common.HexToAddress("0x1111111111111111111111111111111111111111"),
IsCustomGasToken: false,
GasPayingTokenName: "Custom Gas Token",
GasPayingTokenSymbol: "CGT",
},
expectedSchedule: func() *genesis.UpgradeScheduleDeployConfig {
sched := standard.DefaultHardforkScheduleForTag("")
Expand Down Expand Up @@ -114,6 +123,9 @@ func TestCalculateL2GenesisOverrides(t *testing.T) {
"enableGovernance": true,
"governanceTokenOwner": "0x1111111111111111111111111111111111111111",
"l2GenesisInteropTimeOffset": "0x1234",
"isCustomGasToken": false,
"gasPayingTokenName": "Custom Gas Token",
"gasPayingTokenSymbol": "CGT",
},
},
expectError: false,
Expand All @@ -127,6 +139,9 @@ func TestCalculateL2GenesisOverrides(t *testing.T) {
SequencerFeeVaultWithdrawalNetwork: "remote",
EnableGovernance: true,
GovernanceTokenOwner: common.HexToAddress("0x1111111111111111111111111111111111111111"),
IsCustomGasToken: false,
GasPayingTokenName: "Custom Gas Token",
GasPayingTokenSymbol: "CGT",
},
expectedSchedule: func() *genesis.UpgradeScheduleDeployConfig {
sched := standard.DefaultHardforkScheduleForTag("")
Expand Down
1 change: 1 addition & 0 deletions op-deployer/pkg/deployer/pipeline/opchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ func makeDCI(intent *state.Intent, thisIntent *state.ChainIntent, chainID common
DisputeClockExtension: proofParams.DisputeClockExtension, // 3 hours (input in seconds)
DisputeMaxClockDuration: proofParams.DisputeMaxClockDuration, // 3.5 days (input in seconds)
AllowCustomDisputeParameters: proofParams.DangerouslyAllowCustomDisputeParameters,
IsCustomGasToken: thisIntent.CustomGasToken.Enabled,
OperatorFeeScalar: thisIntent.OperatorFeeScalar,
OperatorFeeConstant: thisIntent.OperatorFeeConstant,
}, nil
Expand Down
3 changes: 3 additions & 0 deletions op-deployer/pkg/deployer/standard/standard.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ const (
Eip1559DenominatorCanyon uint64 = 250
Eip1559Denominator uint64 = 50
Eip1559Elasticity uint64 = 6
CustomGasTokenEnabled bool = false
CustomGasTokenName string = ""
CustomGasTokenSymbol string = ""

ContractsV160Tag = "op-contracts/v1.6.0"
ContractsV180Tag = "op-contracts/v1.8.0-rc.4"
Expand Down
19 changes: 17 additions & 2 deletions op-deployer/pkg/deployer/state/chain_intent.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ type L2DevGenesisParams struct {
Prefund map[common.Address]*hexutil.U256 `json:"prefund" toml:"prefund"`
}

type CustomGasToken struct {
Enabled bool `json:"enabled" toml:"enabled"`
Name string `json:"name" toml:"name"`
Symbol string `json:"symbol" toml:"symbol"`
}

type ChainIntent struct {
ID common.Hash `json:"id" toml:"id"`
BaseFeeVaultRecipient common.Address `json:"baseFeeVaultRecipient" toml:"baseFeeVaultRecipient"`
Expand All @@ -70,8 +76,8 @@ type ChainIntent struct {
AdditionalDisputeGames []AdditionalDisputeGame `json:"dangerousAdditionalDisputeGames" toml:"dangerousAdditionalDisputeGames,omitempty"`
OperatorFeeScalar uint32 `json:"operatorFeeScalar,omitempty" toml:"operatorFeeScalar,omitempty"`
OperatorFeeConstant uint64 `json:"operatorFeeConstant,omitempty" toml:"operatorFeeConstant,omitempty"`
L1StartBlockHash *common.Hash `json:"l1StartBlockHash,omitempty" toml:"l1StartBlockHash,omitempty"`

L1StartBlockHash *common.Hash `json:"l1StartBlockHash,omitempty" toml:"l1StartBlockHash,omitempty"`
CustomGasToken *CustomGasToken `json:"customGasToken" toml:"customGasToken"`
// Optional. For development purposes only. Only enabled if the operation mode targets a genesis-file output.
L2DevGenesisParams *L2DevGenesisParams `json:"l2DevGenesisParams,omitempty" toml:"l2DevGenesisParams,omitempty"`
}
Expand Down Expand Up @@ -111,6 +117,15 @@ func (c *ChainIntent) Check() error {
return fmt.Errorf("%w: chainId=%s", ErrFeeVaultZeroAddress, c.ID)
}

if c.CustomGasToken != nil && c.CustomGasToken.Enabled {
if c.CustomGasToken.Name == "" {
return fmt.Errorf("%w: CustomGasToken.Name cannot be empty when enabled, chainId=%s", ErrIncompatibleValue, c.ID)
}
if c.CustomGasToken.Symbol == "" {
return fmt.Errorf("%w: CustomGasToken.Symbol cannot be empty when enabled, chainId=%s", ErrIncompatibleValue, c.ID)
}
}

if c.DangerousAltDAConfig.UseAltDA {
return c.DangerousAltDAConfig.Check(nil)
}
Expand Down
6 changes: 6 additions & 0 deletions op-deployer/pkg/deployer/state/deploy_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ func CombineDeployConfig(intent *Intent, chainIntent *ChainIntent, state *State,
EIP1559Elasticity: chainIntent.Eip1559Elasticity,
},

GasTokenDeployConfig: genesis.GasTokenDeployConfig{
IsCustomGasToken: chainIntent.CustomGasToken.Enabled,
GasPayingTokenName: chainIntent.CustomGasToken.Name,
GasPayingTokenSymbol: chainIntent.CustomGasToken.Symbol,
},

// STOP! This struct sets the _default_ upgrade schedule for all chains.
// Any upgrades you enable here will be enabled for all new deployments.
// In-development hardforks should never be activated here. Instead, they
Expand Down
5 changes: 5 additions & 0 deletions op-deployer/pkg/deployer/state/deploy_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ func TestCombineDeployConfig(t *testing.T) {
UnsafeBlockSigner: common.HexToAddress("0xabc"),
Batcher: common.HexToAddress("0xdef"),
},
CustomGasToken: &CustomGasToken{
Enabled: false,
Name: "Test",
Symbol: "TEST",
},
}
state := State{
SuperchainDeployment: &addresses.SuperchainContracts{ProtocolVersionsProxy: common.HexToAddress("0x123")},
Expand Down
13 changes: 13 additions & 0 deletions op-deployer/pkg/deployer/state/intent.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ func (c *Intent) validateStandardValues() error {
if len(chain.AdditionalDisputeGames) > 0 {
return fmt.Errorf("%w: chainId=%s additionalDisputeGames must be nil", ErrNonStandardValue, chain.ID)
}
if chain.CustomGasToken != nil && (chain.CustomGasToken.Enabled != standard.CustomGasTokenEnabled) {
return fmt.Errorf("%w: chainId=%s custom gas token not allowed in standard configuration", ErrNonStandardValue, chain.ID)
}
}

challenger, _ := standard.ChallengerAddressFor(c.L1ChainID)
Expand Down Expand Up @@ -294,6 +297,11 @@ func NewIntentCustom(l1ChainId uint64, l2ChainIds []common.Hash) (Intent, error)
for _, l2ChainID := range l2ChainIds {
intent.Chains = append(intent.Chains, &ChainIntent{
ID: l2ChainID,
CustomGasToken: &CustomGasToken{
Enabled: standard.CustomGasTokenEnabled,
Name: standard.CustomGasTokenName,
Symbol: standard.CustomGasTokenSymbol,
},
})
}
return intent, nil
Expand Down Expand Up @@ -337,6 +345,11 @@ func NewIntentStandard(l1ChainId uint64, l2ChainIds []common.Hash) (Intent, erro
L1ProxyAdminOwner: l1ProxyAdminOwner,
L2ProxyAdminOwner: l2ProxyAdminOwner,
},
CustomGasToken: &CustomGasToken{
Enabled: standard.CustomGasTokenEnabled,
Name: standard.CustomGasTokenName,
Symbol: standard.CustomGasTokenSymbol,
},
})
}
return intent, nil
Expand Down
45 changes: 45 additions & 0 deletions op-deployer/pkg/deployer/state/intent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ func TestValidateStandardValues(t *testing.T) {
},
ErrIncompatibleValue,
},
{
"CustomGasToken",
func(intent *Intent) {
intent.Chains[0].CustomGasToken = &CustomGasToken{
Enabled: true,
Name: "Custom Gas Token",
Symbol: "CGT",
}
},
ErrNonStandardValue,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -131,6 +142,10 @@ func TestValidateCustomValues(t *testing.T) {
err = intent.Check()
require.NoError(t, err)

setCustomGasToken(&intent)
err = intent.Check()
require.NoError(t, err)

tests := []struct {
name string
mutator func(intent *Intent)
Expand All @@ -155,6 +170,28 @@ func TestValidateCustomValues(t *testing.T) {
},
ErrIncompatibleValue,
},
{
"empty custom gas token name when enabled",
func(intent *Intent) {
intent.Chains[0].CustomGasToken = &CustomGasToken{
Enabled: true,
Name: "",
Symbol: "CGT",
}
},
ErrIncompatibleValue,
},
{
"empty custom gas token symbol when enabled",
func(intent *Intent) {
intent.Chains[0].CustomGasToken = &CustomGasToken{
Enabled: true,
Name: "Custom Gas Token",
Symbol: "",
}
},
ErrIncompatibleValue,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -211,3 +248,11 @@ func setFeeAddresses(intent *Intent) {
intent.Chains[0].L1FeeVaultRecipient = common.HexToAddress("0x09")
intent.Chains[0].SequencerFeeVaultRecipient = common.HexToAddress("0x0A")
}

func setCustomGasToken(intent *Intent) {
intent.Chains[0].CustomGasToken = &CustomGasToken{
Enabled: true,
Name: "Custom Gas Token",
Symbol: "CGT",
}
}
8 changes: 8 additions & 0 deletions op-devstack/sysgo/deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,14 @@ func WithDisputeGameFinalityDelaySeconds(seconds uint64) DeployerOption {
}
}

func WithCustomGasToken(enabled bool, name, symbol string) DeployerOption {
return func(p devtest.P, keys devkeys.Keys, builder intentbuilder.Builder) {
for _, l2Cfg := range builder.L2s() {
l2Cfg.WithCustomGasToken(enabled, name, symbol)
}
}
}

func (wb *worldBuilder) buildL1Genesis() {
wb.require.NotNil(wb.output.L1DevGenesis, "must have L1 genesis outer config")
wb.require.NotNil(wb.output.L1StateDump, "must have L1 genesis alloc")
Expand Down
Loading