nautechsystems/nautilus_trader · error

Wrap amount must be positive

Error message

Wrap amount must be positive

What it means

BlockchainExecutionClient::wrap converts ETH into WETH by depositing amount_wei; a zero deposit is rejected because it cannot satisfy the postcondition of increasing the WETH balance and would waste gas. The library bails early on a zero U256 amount.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:678

            u128::from(self.config.max_fee_per_gas_wei),
        ))
    }

    /// Wraps native currency into the wrapped native token via a WETH `deposit()`
    /// transaction carrying `amount_wei` of native value.
    ///
    /// This is an explicit operator operation; it never runs inside `submit_order`.
    ///
    /// # Errors
    ///
    /// Returns an error if the amount is zero, the WETH target is not a deployed ERC-20 contract,
    /// the client is not connected, another transaction is in flight, no durable store is
    /// configured, the WETH balance does not increase by `amount_wei`, or any RPC, policy, signing,
    /// persistence, or broadcast step fails. A persistence failure after signing, or a failed
    /// postcondition after finality, leaves the in-flight slot occupied.
    pub async fn wrap(&mut self, amount_wei: U256) -> anyhow::Result<B256> {
        if amount_wei.is_zero() {
            anyhow::bail!("Wrap amount must be positive");
        }

        self.ensure_transaction_ready(TransactionPurpose::Wrap)?;

        let calldata = WETH9::depositCall {}.abi_encode();
        let executor = self.transaction_executor()?;
        let included = executor
            .transact(
                self.weth_address,
                amount_wei,
                Bytes::from(calldata),
                TransactionPurpose::Wrap,
                None,
                TransactionAuthorization::Wrap {
                    weth: self.weth_address,
                },
            )
            .await?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Only call wrap when amount_wei > U256::zero(); skip the call otherwise
  2. Recompute the intended wrap amount and guard against Decimal-to-U256 truncation to zero
  3. Check the upstream calculation (e.g. excess balance logic) for underflow to zero

Example fix

// before
client.wrap(U256::ZERO).await?;
// after
if amount_wei.is_zero() {
    return Ok(None); // nothing to wrap
}
let tx_hash = client.wrap(amount_wei).await?;
Defensive patterns

Strategy: try-catch

Validate before calling

if amount_wei.is_zero() {
    // skip wrap entirely
    return Ok(None);
}

Type guard

fn is_positive_amount(a: &U256) -> bool { !a.is_zero() }

Try / catch

if amount_wei.is_zero() { return Ok(()); }
match client.wrap(amount_wei).await {
    Ok(tx_hash) => info!("wrap tx: {tx_hash}"),
    Err(e) => error!("wrap failed: {e}"),
}

Prevention

When it happens

Trigger: Calling client.wrap(U256::ZERO), or wrap with an amount computed to zero (e.g. balance-minus-reserve arithmetic underflowing to 0).

Common situations: Wrapping a computed 'excess ETH' amount that is actually zero; passing a U256 default/zero initializer by mistake; converting a Decimal human amount to wei with truncation to 0.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/83a59d9f3254a969. Report an issue: GitHub.