Skip to content
Open
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
f14d554
eth/backend: Enable gasless transactions by default in txpool and miner
sledro Apr 25, 2025
60393ae
core/state_transition: Implement gasless transaction support and enha…
sledro Apr 25, 2025
62d5c34
miner: Enhance transaction filtering to support zero-fee transactions
sledro Apr 25, 2025
e02a2b2
miner: Update transaction ordering logic to handle zero-fee transactions
sledro Apr 25, 2025
5bd11e9
core/txpool: Add TODO for gasless transaction validation enhancements
sledro Apr 25, 2025
421f068
core/state_transition: Add TODO for gasless transaction gas tip handling
sledro Apr 25, 2025
eaccbf6
core/types: Add isGaslessTx method to transaction types
sledro Apr 26, 2025
33c1689
core/txpool: Enhance gasless transaction validation and gas price checks
sledro Apr 26, 2025
cdfcc58
core/txpool: Skip gasless transactions in pending list filtering & en…
sledro Apr 26, 2025
f60d354
core/state_transition: Add IsGaslessTx field to Message struct and up…
sledro Apr 26, 2025
7590f0d
miner: Remove unnecessary blank line in fillTransactions function
sledro Apr 26, 2025
9595d34
miner: Update transaction ordering logic to use IsGaslessTx for gasle…
sledro Apr 26, 2025
233909f
core/state_transition: Update to use IsGaslessTx
sledro Apr 26, 2025
e48fb61
Update .gitignore to include devdata, password.txt, and plain_key.txt
sledro Apr 28, 2025
8cc4298
core/genesis: Initialize GaslessRegistry in DeveloperGenesisBlock
sledro Apr 30, 2025
aaf52a1
core/txpool: Implement gasless transaction validation logic
sledro Apr 30, 2025
7187a5f
core/genesis, core/txpool, params: Rename GaslessRegistry to GasStation
sledro Apr 30, 2025
0d41faa
core/state_transition: Implement gas station credit charging for gasl…
sledro Apr 30, 2025
0aeb0ba
remove whitespace
sledro May 13, 2025
b9651da
core/txpool: Enhance gasless transaction validation with pending cred…
sledro May 19, 2025
bb18aba
add build steps
sledro May 19, 2025
cce28e8
Update GasStationAddress to retrieve value from environment variable …
sledro May 20, 2025
ea50c87
move github workflow to correct location
sledro May 20, 2025
33c7031
temp remove testing on build
sledro May 20, 2025
f7b2e74
remove mutex as pool is already locked
sledro May 22, 2025
d544e64
core/types: Add handling for gasless transactions in RollupCostData
sledro May 22, 2025
08bad5c
core/state_transition: Fix gas handling for gasless transactions
sledro May 22, 2025
3bfd0f3
core/state_transition: Adjust gas allocation for gasless transactions
sledro May 22, 2025
dd83eac
core/types/receipt: Include gasless transaction handling in DeriveFie…
sledro May 23, 2025
d298bf1
core/state_transition: Refine gas allocation for gasless transactions
sledro May 23, 2025
dd7c785
core/state_transition: Implement GasStation storage slot calculations…
sledro May 24, 2025
92fdad2
core/state_transition: Emit CreditsUsed event for gasless transactions
sledro May 24, 2025
c31d25f
core/state_transition: Refactor gas handling for gasless transactions
sledro May 24, 2025
e49ea72
core/txpool: Refactor pending credit usage management for gasless tra…
sledro May 24, 2025
710577b
core/state_transition: Clean up buyGas method by removing unnecessary…
sledro May 24, 2025
e19a224
core/txpool: Fix pending credit usage decrement for gasless transactions
sledro May 24, 2025
75fb049
core/txpool: Enhance pending credit usage management for gasless tran…
sledro May 25, 2025
d8395f6
core/state_transition: Update innerExecute to handle gasless transact…
sledro Jun 4, 2025
6ec926e
core/state_transition: Refactor gas handling logic in innerExecute fo…
sledro Jun 4, 2025
9a0dcd7
core/txpool: Refactor validation logic for gasless transactions
sledro Jun 4, 2025
5e1029f
Update GitHub Actions workflow to use new output syntax for versioning
sledro Jun 4, 2025
bf4b5a2
core/state_transition: Update gas station storage slot calculations
sledro Jun 4, 2025
911be36
Update GasStationCode in protocol_params.go for gasless transactions
sledro Jun 4, 2025
41c9f05
Fix typo in validation comment for gasless transactions in txpool
sledro Jun 4, 2025
a4fbb67
core/txpool: Initialize pending credit usage map in LegacyPool
sledro Jun 4, 2025
c759aa8
core/gas_station: Implement GasStation logic for gasless transactions
sledro Jun 5, 2025
b32dca2
core/state_transition: Enhance gasless transaction handling and valid…
sledro Jun 5, 2025
61de7f6
core/gas_station: Refactor gasless transaction validation interface
sledro Jun 6, 2025
a6cd075
core/state_transition: Refactor gas usage handling in innerExecute
sledro Jun 6, 2025
51320ba
core/gas_station: Add event signature for CreditsUsed event
sledro Jun 6, 2025
dd7f0f8
core/gas_station: Introduce pre-built arguments for CreditsUsed event
sledro Jun 6, 2025
1af1616
core/gas_station: Add validation for non-zero gas limit in gasless tr…
sledro Jun 6, 2025
02a2c16
core/state_transition: Simplify event logging in innerExecute method
sledro Jun 6, 2025
01f9348
core/gas_station: Update gas station storage location calculation
sledro Jun 6, 2025
85498de
core/gas_station: Add single-use mode and user tracking for gasless t…
sledro Jun 6, 2025
9d017b3
core/gas_station: Refactor storage slot calculation for nested mappings
sledro Jun 6, 2025
0385360
core/gas_station: Update gas station storage location calculation to …
sledro Jul 28, 2025
80f6d79
core/state_transition: ensure gasless tx uses same gas amount as stan…
sledro Aug 5, 2025
31b7db9
core/gas_station_test: Add tests for gasless transaction gas usage
sledro Aug 5, 2025
d8f9205
Update rollup cost tests to use transactions with gas price
sledro Aug 5, 2025
2735c7e
Refactor GitHub Actions workflow for Go tests
sledro Aug 5, 2025
5fc91fa
Fix gas price handling in EIP155 transition tests
sledro Aug 5, 2025
b44e5ec
remove emit credit used event to align with reth
sledro Aug 27, 2025
3df3691
temp disable tests
sledro Aug 27, 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
89 changes: 89 additions & 0 deletions .github/workflows/build_and_publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Test, Build Image & Push to ECR

on:
push:
branches:
- main # Trigger the workflow on pushes to the main branch
tags:
- "**" # Trigger the workflow on tags including hierarchical tags like v1.0/beta
pull_request:
types: [opened, synchronize] # Trigger the workflow when a PR is opened or updated

env:
RELEASE_REVISION: ${{ github.sha }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.AWS_REGION }}
ECR_REPOSITORY: ll-geth

Comment on lines +12 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Stop exporting AWS secrets as top-level env; pass secrets directly to the action.

Top-level env propagates to all steps (including shell), increasing leak risk. Feed secrets directly into aws-actions instead.

Apply these diffs:

-env:
-  RELEASE_REVISION: ${{ github.sha }}
-  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
-  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
-  AWS_REGION: ${{ secrets.AWS_REGION }}
-  ECR_REPOSITORY: ll-geth
+env:
+  ECR_REPOSITORY: ll-geth
       - name: Configure AWS credentials
         uses: aws-actions/configure-aws-credentials@v4
         with:
-          aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }}
-          aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY }}
-          aws-region: ${{ env.AWS_REGION }}
+          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
+          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+          aws-region: ${{ secrets.AWS_REGION }}

Also applies to: 44-50

🤖 Prompt for AI Agents
In .github/workflows/build_and_publish.yml around lines 12-18 (and similarly
lines 44-50), the workflow exports AWS secrets as top-level env which exposes
them to every step; remove AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and
AWS_REGION (and any secret ECR_* values) from the top-level env block and
instead pass them directly to the aws-actions step(s) via the step's with: or
env: entries (e.g., aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }},
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}, aws-region: ${{
secrets.AWS_REGION }}), keeping only non-secret values like RELEASE_REVISION at
the top level; update both occurrences (lines 12-18 and 44-50) accordingly.

jobs:
# test:
# name: Run Go Tests
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4

# - name: Set up Go
# uses: actions/setup-go@v5
# with:
# go-version: 1.21.5

# - name: Test
# run: go test -v ./...

release:
# needs: test
name: Build Image & Push to ECR
runs-on: ubuntu-latest
steps:
Comment on lines +34 to +38
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Gate ECR push on push-events to main/tags only.

Avoid attempting to push on pull_request events and from forks.

Apply:

   release:
+    if: github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/main') || startsWith(github.ref, 'refs/tags/'))
     # needs: test
     name: Build Image & Push to ECR
     runs-on: ubuntu-latest
+    permissions:
+      contents: read
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
release:
# needs: test
name: Build Image & Push to ECR
runs-on: ubuntu-latest
steps:
release:
if: github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/main') || startsWith(github.ref, 'refs/tags/'))
# needs: test
name: Build Image & Push to ECR
runs-on: ubuntu-latest
permissions:
contents: read
steps:
🤖 Prompt for AI Agents
In .github/workflows/build_and_publish.yml around lines 34-38, the release job
currently runs for events that include pull_request/forks; change its gating so
ECR push runs only for push events to main or tag refs. Update the workflow
triggers or add a job-level condition: require github.event_name == 'push' and
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')), so
the job is skipped for pull_request events and forked PRs; ensure any
push-to-ECR steps are behind that condition.

- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.sha }}

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}

- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3

- name: Docker cache layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-single-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-single-buildx

- name: Get the version tag or short SHA
id: get-tag
run: |
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
else
echo "version=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
fi

- name: Push Image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ steps.get-tag.outputs.version }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new
build-args: VERSION=${{ steps.get-tag.outputs.version }}

- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,6 @@ profile.cov
.vscode

tests/spec-tests/
devdata/
password.txt
plain_key.txt
123 changes: 123 additions & 0 deletions core/gas_station.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package core

import (
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)

// GasStation struct storage slots structs
type GasStationStorageSlots struct {
StructBaseSlotHash common.Hash
CreditSlotHash common.Hash
WhitelistEnabledSlotHash common.Hash
NestedWhitelistMapBaseSlotHash common.Hash
}

// calculateGasStationSlots computes the storage slot hashes for a specific
// registered contract within the GasStation's `contracts` mapping.
// It returns the base slot for the struct (holding packed fields), the slot for credits,
// the slot for whitelistEnabled, and the base slot for the nested whitelist mapping.
func CalculateGasStationSlots(registeredContractAddress common.Address) GasStationStorageSlots {
gasStationStorageSlots := GasStationStorageSlots{}

// ERC-7201 storage location for GasStationStorage
// bytes32 private constant GasStationStorageLocation = 0xc2eaf2cedf9e23687c6eb7c4717aa3eacbd015cc86eaad3f51aae2d3c955db00;
gasStationStorageLocation := common.HexToHash("0xc2eaf2cedf9e23687c6eb7c4717aa3eacbd015cc86eaad3f51aae2d3c955db00")

// The 'contracts' mapping is at offset 1 from the storage location
// (dao is at offset 0, contracts is at offset 1)
contractsMapSlot := new(big.Int).Add(gasStationStorageLocation.Big(), big.NewInt(1))

// Calculate the base slot for the struct entry in the mapping
keyPadded := common.LeftPadBytes(registeredContractAddress.Bytes(), 32)
mapSlotPadded := common.LeftPadBytes(contractsMapSlot.Bytes(), 32)
combined := append(keyPadded, mapSlotPadded...)
gasStationStorageSlots.StructBaseSlotHash = crypto.Keccak256Hash(combined)

// Calculate subsequent slots by adding offsets to the base slot hash
// New struct layout: bool registered, bool active, address admin (all packed in slot 0)
// uint256 credits (slot 1), bool whitelistEnabled (slot 2), mapping whitelist (slot 3)
structBaseSlotBig := gasStationStorageSlots.StructBaseSlotHash.Big()

// Slot for 'credits' (offset 1 from base - after the packed bools and address)
creditsSlotBig := new(big.Int).Add(structBaseSlotBig, big.NewInt(1))
gasStationStorageSlots.CreditSlotHash = common.BigToHash(creditsSlotBig)

// Slot for 'whitelistEnabled' (offset 2 from base)
whitelistEnabledSlotBig := new(big.Int).Add(structBaseSlotBig, big.NewInt(2))
gasStationStorageSlots.WhitelistEnabledSlotHash = common.BigToHash(whitelistEnabledSlotBig)

// Base slot for the nested 'whitelist' mapping (offset 3 from base)
nestedWhitelistMapBaseSlotBig := new(big.Int).Add(structBaseSlotBig, big.NewInt(3))
gasStationStorageSlots.NestedWhitelistMapBaseSlotHash = common.BigToHash(nestedWhitelistMapBaseSlotBig)

return gasStationStorageSlots
}

func ValidateGaslessTx(to *common.Address, from common.Address, gasLimit uint64, sdb *state.StateDB) (*big.Int, *big.Int, *GasStationStorageSlots, error) {
if to == nil {
return nil, nil, nil, fmt.Errorf("gasless txn must have a valid to address")
}

// Calculate GasStation storage slots
gasStationStorageSlots := CalculateGasStationSlots(*to)

// Get the storage for the GaslessContract struct for the given address
storageBaseSlot := sdb.GetState(params.GasStationAddress, gasStationStorageSlots.StructBaseSlotHash)

// Extract the registered and active bytes from the storage slot
isRegistered := storageBaseSlot[31] == 0x01
isActive := storageBaseSlot[30] == 0x01

if !isRegistered {
return nil, nil, nil, fmt.Errorf("gasless transaction to unregistered address")
}

if !isActive {
return nil, nil, nil, fmt.Errorf("gasless transaction to inactive address")
}

// Get the available credits from the credits storage slot in the GasStation contract for the given address
availableCredits := sdb.GetState(params.GasStationAddress, gasStationStorageSlots.CreditSlotHash)

// Convert credits (Hash) and tx gas (uint64) to big.Int for comparison
availableCreditsBig := new(big.Int).SetBytes(availableCredits.Bytes())
txRequiredCreditsBig := new(big.Int).SetUint64(gasLimit)

// Check if contract has enough available credits to cover the cost of the tx
if availableCreditsBig.Cmp(txRequiredCreditsBig) < 0 {
return nil, nil, nil, fmt.Errorf("gasless transaction has insufficient credits: have %v, need %v", availableCreditsBig, txRequiredCreditsBig)
}

// Get the whitelist enabled slot
whitelistEnabled := sdb.GetState(params.GasStationAddress, gasStationStorageSlots.WhitelistEnabledSlotHash)

// Get the whitelist enabled byte from the whitelist enabled slot
isWhitelistEnabled := whitelistEnabled[31] == 0x01

if isWhitelistEnabled {
// Calculate slot for the specific user in the nested whitelist map
userKeyPadded := common.LeftPadBytes(from.Bytes(), 32)
mapBaseSlotPadded := common.LeftPadBytes(gasStationStorageSlots.NestedWhitelistMapBaseSlotHash.Bytes(), 32)
userCombined := append(userKeyPadded, mapBaseSlotPadded...)
userWhitelistSlotHash := crypto.Keccak256Hash(userCombined)

// Get the whitelist status for the specific user
userWhitelist := sdb.GetState(params.GasStationAddress, userWhitelistSlotHash)

// Check if the user is whitelisted
userWhitelistByte := userWhitelist[31]
isUserWhitelistStorage := userWhitelistByte == 0x01

if !isUserWhitelistStorage {
return nil, nil, nil, fmt.Errorf("gasless transaction to non-whitelisted address")
}
}

return availableCreditsBig, txRequiredCreditsBig, &gasStationStorageSlots, nil
}
2 changes: 2 additions & 0 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
params.WithdrawalQueueAddress: {Nonce: 1, Code: params.WithdrawalQueueCode, Balance: common.Big0},
params.ConsolidationQueueAddress: {Nonce: 1, Code: params.ConsolidationQueueCode, Balance: common.Big0},
// Initialize GasStation: Set Nonce and Code, storage init empty (nil map)
params.GasStationAddress: {Nonce: 1, Code: params.GasStationCode, Balance: common.Big0, Storage: nil},
},
}
if faucet != nil {
Expand Down
64 changes: 63 additions & 1 deletion core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ import (
"math"
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
Expand Down Expand Up @@ -169,6 +172,7 @@ type Message struct {
IsDepositTx bool // IsDepositTx indicates the message is force-included and can persist a mint.
Mint *big.Int // Mint is the amount to mint before EVM processing, or nil if there is no minting.
RollupCostData types.RollupCostData // RollupCostData caches data to compute the fee we charge for data availability
IsGaslessTx bool // IsGaslessTx indicates the message is a gasless transaction.
}

// TransactionToMessage converts a transaction into a Message.
Expand All @@ -193,6 +197,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
IsDepositTx: tx.IsDepositTx(),
Mint: tx.Mint(),
RollupCostData: tx.RollupCostData(),
IsGaslessTx: tx.IsGaslessTx(),
}
// If baseFee provided, set gasPrice to effectiveGasPrice.
if baseFee != nil {
Expand Down Expand Up @@ -371,6 +376,20 @@ func (st *stateTransition) preCheck() error {
return fmt.Errorf("%w: address %v, len(code): %d", ErrSenderNoEOA, msg.From.Hex(), len(code))
}
}

// Give EVM gas for free if gasless txn
if st.msg.IsGaslessTx {
// Validate gasless transaction requirements first
_, _, _, err := ValidateGaslessTx(st.msg.To, st.msg.From, st.msg.GasLimit, st.state.(*state.StateDB))
if err != nil {
return err
}

st.initialGas = st.msg.GasLimit
st.gasRemaining += st.msg.GasLimit
return st.gp.SubGas(st.msg.GasLimit)
}

// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) {
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
Expand Down Expand Up @@ -628,10 +647,53 @@ func (st *stateTransition) innerExecute() (*ExecutionResult, error) {
}
st.returnGas()

// Handle gasless transaction credit deduction AFTER refunds are applied
if msg.IsGaslessTx {
// Calculate GasStation storage slots (validation already done in preCheck)
gasStationStorageSlots := CalculateGasStationSlots(*msg.To)
availableCredits := st.state.GetState(params.GasStationAddress, gasStationStorageSlots.CreditSlotHash)

// Convert credits (Hash) and tx gas (uint64) to big.Int for comparison
// Use the final gas used amount (after refunds are applied)
availableCreditsBig := new(big.Int).SetBytes(availableCredits.Bytes())
txRequiredCreditsBig := new(big.Int).SetUint64(st.gasUsed())

// Deduct the credits from the contract state directly
st.state.SetState(params.GasStationAddress, gasStationStorageSlots.CreditSlotHash, common.BigToHash(new(big.Int).Sub(availableCreditsBig, txRequiredCreditsBig)))

// Emit CreditsUsed event: CreditsUsed(address indexed contractAddress, address caller, uint256 gasUsed)
// Create ABI arguments for non-indexed parameters
addressType, _ := abi.NewType("address", "", nil)
uint256Type, _ := abi.NewType("uint256", "", nil)
arguments := abi.Arguments{
{Type: addressType}, // caller (not indexed)
{Type: uint256Type}, // gasUsed (not indexed)
}

// ABI encode the non-indexed data
data, err := arguments.Pack(st.msg.From, big.NewInt(int64(st.gasUsed())))
if err != nil {
// Fallback to manual encoding if ABI encoding fails
data = append(
common.LeftPadBytes(st.msg.From.Bytes(), 32),
common.LeftPadBytes(big.NewInt(int64(st.gasUsed())).Bytes(), 32)...,
)
}

st.state.AddLog(&types.Log{
Address: params.GasStationAddress,
Topics: []common.Hash{
crypto.Keccak256Hash([]byte("CreditsUsed(address,address,uint256)")), // Event signature
common.BytesToHash(st.msg.To.Bytes()), // contractAddress (indexed)
},
Data: data,
})
}

// OP-Stack: Note for deposit tx there is no ETH refunded for unused gas, but that's taken care of by the fact that gasPrice
// is always 0 for deposit tx. So calling refundGas will ensure the gasUsed accounting is correct without actually
// changing the sender's balance.
if st.msg.IsDepositTx && rules.IsOptimismRegolith {
if (st.msg.IsDepositTx && rules.IsOptimismRegolith) || st.msg.IsGaslessTx {
// Skip coinbase payments for deposit tx in Regolith
return &ExecutionResult{
UsedGas: st.gasUsed(),
Expand Down
Loading