diff --git a/Engine/Enums.php b/Engine/Enums.php index 2ff2518..92cafb7 100644 --- a/Engine/Enums.php +++ b/Engine/Enums.php @@ -72,8 +72,12 @@ enum FeeRenderModel: string case LastEventToTheVoid = 'LastEventToTheVoid'; // The fee is the last event to the special `the-void` address (see `bitcoin-main`) // If the fee is 0, there's no event to `the-void` case ExtraF = 'ExtraF'; // If transaction has an event with `f` in extra data, this is the fee + case ExtraFCaret = 'ExtraF^'; // Same as `ExtraF`, but all events with extras starting with `f` should also be + // treated as fees (no example usage yet) case ExtraBF = 'ExtraBF'; // Same as `ExtraF`, but there can be two events: `f` is the fee paid to the miner, and - // `b` is the part which is being burnt (see `ethereum-main`) + // `b` is the part which is being burnt (see `tron-main`) + case ExtraBFCaret = 'ExtraBF^'; // Same as `ExtraBF`, but all events with extras starting with `f` should also be + // treated as fees (see `ethereum-main`) } // We use virtual block number for processing mempool diff --git a/Modules/BaseMainModule.php b/Modules/BaseMainModule.php index 5c61b23..8c0acb5 100644 --- a/Modules/BaseMainModule.php +++ b/Modules/BaseMainModule.php @@ -22,10 +22,12 @@ function initialize() // EVMMainModule $this->evm_implementation = EVMImplementation::geth; - $this->extra_features = [EVMSpecialFeatures::HasSystemTransactions]; // Base is a fork of Optimism, so it has the same special txs + $this->extra_features = [EVMSpecialFeatures::HasSystemTransactions, EVMSpecialFeatures::OPStackBaseFeeRecipient, EVMSpecialFeatures::OPStackL1FeeVault]; // Base is a fork of Optimism, so it has the same special txs $this->reward_function = function($block_id) { return '0'; }; + $this->l1_fee_vault = '0x420000000000000000000000000000000000001a'; // https://github.com/ethereum-optimism/op-geth/blob/c6ea6fa09d4e7df6d1ca6b2d32bcb139f021b1e2/params/protocol_params.go#L29 as it uses the same code base + $this->base_fee_recipient = '0x4200000000000000000000000000000000000019'; } } diff --git a/Modules/Common/EVMMainModule.php b/Modules/Common/EVMMainModule.php index 6bb75b2..396bada 100644 --- a/Modules/Common/EVMMainModule.php +++ b/Modules/Common/EVMMainModule.php @@ -17,7 +17,7 @@ abstract class EVMMainModule extends CoreModule public ?TransactionRenderModel $transaction_render_model = TransactionRenderModel::Even; public ?CurrencyFormat $currency_format = CurrencyFormat::Static; public ?CurrencyType $currency_type = CurrencyType::FT; - public ?FeeRenderModel $fee_render_model = FeeRenderModel::ExtraBF; + public ?FeeRenderModel $fee_render_model = FeeRenderModel::ExtraBFCaret; public ?array $special_addresses = ['the-void']; public ?PrivacyModel $privacy_model = PrivacyModel::Transparent; @@ -34,6 +34,7 @@ abstract class EVMMainModule extends CoreModule EVMSpecialTransactions::ContractCreation->value => 'Contract creation', EVMSpecialTransactions::ContractDestruction->value => 'Contract destruction', EVMSpecialTransactions::Withdrawal->value => 'Withdrawal', + EVMSpecialTransactions::L1Fee->value => 'L1 fee' ]; public ?bool $should_return_events = true; @@ -49,6 +50,8 @@ abstract class EVMMainModule extends CoreModule public array $extra_features = []; public ?string $staking_contract = null; public ?Closure $reward_function = null; + public ?string $l1_fee_vault = null; + public ?string $base_fee_recipient = null; // @@ -80,6 +83,12 @@ final public function post_post_initialize() $this->block_entity_name = 'batch'; // We process batches instead of blocks $this->mempool_entity_name = 'queue'; // Unfinalized batches are processed as "mempool" } + + if (in_array(EVMSpecialFeatures::OPStackL1FeeVault, $this->extra_features) && is_null($this->l1_fee_vault)) + throw new DeveloperError('`l1_fee_vault` should be set for `OPStackL1FeeVault` chains'); + + if (in_array(EVMSpecialFeatures::OPStackBaseFeeRecipient, $this->extra_features) && is_null($this->base_fee_recipient) ) + throw new DeveloperError('`base_fee_recipient` should be set for `OPStackBaseFeeRecipient` chains'); } final public function pre_process_block($block_id) @@ -272,6 +281,9 @@ final public function pre_process_block($block_id) $transaction_data[($general_data[$i]['hash'])]['blobGasPrice'] = $receipt_data[$i]['blobGasPrice'] ?? null; $transaction_data[($general_data[$i]['hash'])]['blobGasUsed'] = $receipt_data[$i]['blobGasUsed'] ?? null; } + + if (in_array(EVMSpecialFeatures::OPStackL1FeeVault, $this->extra_features)) + $transaction_data[($general_data[$i]['hash'])]['l1Fee'] = $receipt_data[$i]['l1Fee'] ?? null; } } else // Mempool processing @@ -399,6 +411,7 @@ final public function pre_process_block($block_id) $this_gas_used = to_int256_from_0xhex($transaction['gasUsed']); $this_burned = (!is_null($base_fee_per_gas)) ? bcmul($base_fee_per_gas, $this_gas_used) : '0'; $this_to_miner = bcsub(bcmul(to_int256_from_0xhex($transaction['effectiveGasPrice']), $this_gas_used), $this_burned); + $this_l1_fee = ((isset($transaction['l1Fee']) && !is_null($transaction['l1Fee'])) ? to_int256_from_0xhex($transaction['l1Fee']) : '0'); if (in_array(EVMSpecialFeatures::EffectiveGasPriceCanBeZero, $this->extra_features)) if ($transaction['effectiveGasPrice'] === '0x0') @@ -435,6 +448,7 @@ final public function pre_process_block($block_id) } // Burning + if ($this_burned !== '0') { $events[] = [ @@ -449,16 +463,17 @@ final public function pre_process_block($block_id) $events[] = [ 'transaction' => $transaction_hash, - 'address' => '0x00', + 'address' => !in_array(EVMSpecialFeatures::OPStackBaseFeeRecipient, $this->extra_features) ? '0x00' : $this->base_fee_recipient, 'sort_in_block' => $ijk, 'sort_in_transaction' => 1, 'effect' => $this_burned, 'failed' => false, - 'extra' => EVMSpecialTransactions::Burning->value, + 'extra' => !in_array(EVMSpecialFeatures::OPStackBaseFeeRecipient, $this->extra_features) ? EVMSpecialTransactions::Burning->value : EVMSpecialTransactions::BaseFee->value, ]; } // Miner fee + if ($this_to_miner !== '0') { $events[] = [ @@ -487,13 +502,38 @@ final public function pre_process_block($block_id) ]; } + // L1 fees + + if (in_array(EVMSpecialFeatures::OPStackL1FeeVault, $this->extra_features) && $this_l1_fee !== '0') + { + $events[] = [ + 'transaction' => $transaction_hash, + 'address' => $transaction['from'], + 'sort_in_block' => $ijk, + 'sort_in_transaction' => 4, + 'effect' => '-' . $this_l1_fee, + 'failed' => false, + 'extra' => EVMSpecialTransactions::L1Fee->value, + ]; + + $events[] = [ + 'transaction' => $transaction_hash, + 'address' => $this->l1_fee_vault, + 'sort_in_block' => $ijk, + 'sort_in_transaction' => 5, + 'effect' => $this_l1_fee, + 'failed' => false, + 'extra' => EVMSpecialTransactions::L1Fee->value, + ]; + } + // The transfer itself $events[] = [ 'transaction' => $transaction_hash, 'address' => $transaction['from'], 'sort_in_block' => $ijk, - 'sort_in_transaction' => 4, + 'sort_in_transaction' => 6, 'effect' => '-' . to_int256_from_0xhex($transaction['value']), 'failed' => ($transaction['status'] === '0x1') ? false : true, 'extra' => null, @@ -525,7 +565,7 @@ final public function pre_process_block($block_id) 'transaction' => $transaction_hash, 'address' => $recipient, 'sort_in_block' => $ijk++, - 'sort_in_transaction' => 5, + 'sort_in_transaction' => 7, 'effect' => to_int256_from_0xhex($transaction['value']), 'failed' => ($transaction['status'] === '0x1') ? false : true, 'extra' => $extra_bit, diff --git a/Modules/Common/EVMTraits.php b/Modules/Common/EVMTraits.php index 986e269..da46248 100644 --- a/Modules/Common/EVMTraits.php +++ b/Modules/Common/EVMTraits.php @@ -22,6 +22,8 @@ enum EVMSpecialTransactions: string case ContractCreation = 'c'; case ContractDestruction = 'd'; case Withdrawal = 'w'; + case L1Fee = 'f1'; // Optimism + case BaseFee = 'fb'; // Optimism } enum EVMSpecialFeatures @@ -38,6 +40,9 @@ enum EVMSpecialFeatures case rskEVM; // Rootstock has different traces and deferred validators rewards (in N+4000 block). case TraceBlockSupport; // Support for `trace_block` in RPC API case EIP4844; // Support of blob transaction + case OPStackL1FeeVault; // Optimistic rollups + case OPStackBaseFeeRecipient; // Optimistic rollups + } trait EVMTraits diff --git a/Modules/OptimismMainModule.php b/Modules/OptimismMainModule.php index 7e65ee0..f99911c 100644 --- a/Modules/OptimismMainModule.php +++ b/Modules/OptimismMainModule.php @@ -22,11 +22,13 @@ function initialize() // EVMMainModule $this->evm_implementation = EVMImplementation::geth; - $this->extra_features = [EVMSpecialFeatures::HasSystemTransactions]; + $this->extra_features = [EVMSpecialFeatures::HasSystemTransactions, EVMSpecialFeatures::OPStackBaseFeeRecipient, EVMSpecialFeatures::OPStackL1FeeVault]; $this->reward_function = function($block_id) { return '0'; }; + $this->l1_fee_vault = '0x420000000000000000000000000000000000001a'; // https://github.com/ethereum-optimism/op-geth/blob/c6ea6fa09d4e7df6d1ca6b2d32bcb139f021b1e2/params/protocol_params.go#L29 + $this->base_fee_recipient = '0x4200000000000000000000000000000000000019'; // Handles $this->handles_implemented = true; diff --git a/Modules/opBNBMainModule.php b/Modules/opBNBMainModule.php index 1e637a4..1d7922a 100644 --- a/Modules/opBNBMainModule.php +++ b/Modules/opBNBMainModule.php @@ -22,10 +22,13 @@ function initialize() // EVMMainModule $this->mempool_implemented = false; $this->evm_implementation = EVMImplementation::geth; - $this->extra_features = [EVMSpecialFeatures::HasSystemTransactions]; + $this->extra_features = [EVMSpecialFeatures::HasSystemTransactions, EVMSpecialFeatures::OPStackBaseFeeRecipient, EVMSpecialFeatures::OPStackL1FeeVault]; $this->reward_function = function($block_id) { return '0'; }; + + $this->l1_fee_vault = '0x420000000000000000000000000000000000001a'; // https://github.com/bnb-chain/op-geth/blob/aead14eeda87794899daed7fbdcca11fb9021fbd/params/protocol_params.go#L29 + $this->base_fee_recipient = '0x4200000000000000000000000000000000000019'; } }