Assessment reports>Astria Geth>Findings>Incorrect ERC-20 deposit handling

Incorrect ERC-20 deposit handling

  • Target: state_transition.go

  • Category: Coding Mistakes

  • Severity: High

  • Likelihood: N/A

  • Impact: Informational

Description

The pull request under review rebases Astria preexisting changes on top of official Geth 1.14.3. At the time of the start of this engagement, PR #21 HEAD was at commit a30fd3d23b31dff26ded8abf373e0bc8050d08c7. During the first two days of our engagement, Astria independently found and fixed some issues (seemingly originating from incorrect manual merge-conflict resolutions), updating the PR HEAD to 5f9724be5ad41500855c9c6e6f76037e438f320c. This included a relatively severe issue in state_transition.go::TransitionDb.

The function was modified by Astria to handle the newly introduced deposit-transaction type. In the initial version of the code, the function code appeared as follows:

func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
    // if this is a deposit tx, we only need to mint funds and no gas is used.
    if st.msg.IsDepositTx {
        log.Debug("deposit tx minting funds", "to", *st.msg.To, "value", st.msg.Value)
        st.state.AddBalance(*st.msg.To, uint256.MustFromBig(st.msg.Value), tracing.BalanceIncreaseAstriaDepositTx)
        return &ExecutionResult{
            UsedGas:    0,
            Err:        nil,
            ReturnData: nil,
        }, nil
    }

    if st.msg.IsDepositTx {
        st.initialGas = st.msg.GasLimit
        st.gasRemaining = st.msg.GasLimit
        log.Debug("deposit tx minting erc20", "to", *st.msg.To, "value", st.msg.Value)
    }
    /// ...

The initial condition is intended to handle only native deposit transactions, and it was incorrect. ERC-20 deposits always have a msg.Value of zero but a nonempty msg.Data containing the calldata, which invokes the mint function of the destination contract that manages the bridged asset.

Impact

The TransitionDb function was incorrectly handling ERC-20 deposit transactions as native deposit transactions. This would have prevented successful bridging of ERC-20 assets, leading to the loss of the deposited assets.

Recommendations

None. (The issue was already independently found and fixed.)

Remediation

This issue has been acknowledged by Astria, and a fix was implemented in commit 5f9724be.

The issue was fixed as follows:

func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
    // if this is a deposit tx, we only need to mint funds and no gas is used.
-   if st.msg.IsDepositTx {
+   if st.msg.IsDepositTx && len(st.msg.Data) == 0 {
        log.Debug("deposit tx minting funds", "to", *st.msg.To, "value", st.msg.Value)
        st.state.AddBalance(*st.msg.To, uint256.MustFromBig(st.msg.Value), tracing.BalanceIncreaseAstriaDepositTx)
        return &ExecutionResult{
            UsedGas:    0,
            Err:        nil,
            ReturnData: nil,
        }, nil
    }

    if st.msg.IsDepositTx {
        st.initialGas = st.msg.GasLimit
        st.gasRemaining = st.msg.GasLimit
        log.Debug("deposit tx minting erc20", "to", *st.msg.To, "value", st.msg.Value)
    }
    /// ...
Zellic © 2025Back to top ↑