Ethereum Foundry Script: Balance Mismatch Error
As a developer working with Ethereum smart contracts, it is essential to ensure that your scripts are working properly and are accurately tracking account balances. However, there are often oversights that can lead to issues such as balance mismatch. In this article, we will delve into the “balance mismatch” error in Foundry and provide guidance on how to reproduce and resolve it.
What is a balance mismatch?
A balance mismatch occurs when the actual balance of an account on the blockchain differs from its displayed balance as shown to the caller of the function used to track the balance of that account. This can happen for a variety of reasons, including:
- Broadcasting incorrect transactions
- Conflicting balances between accounts (e.g. due to reentrancy attacks)
- Incorrect contract code or logic
Reproduction of foundry scripts
The following foundry script demonstrates a balance mismatch error:
MyContract contract {
fn myFunction() -> Balance {
// Simulating some transactions
let tx1 = Tx::new(&[Address::from(0x123456789)), 100);
let tx2 = Tx::new(&[Address::from(0x234567890)], 200);
foundry_script {
vm.startBroadcast(Address::from(0x345678901));
vm.gather();
Balance::new().balance() // Should return the caller's balance
.if_eq(expectedBalance);
expectedBalance
}
}
fn myFunction2() -> Balance {
let tx1 = Tx::new(&[Address::from(0x123456789)], 100);
foundry_script {
vm.startBroadcast(Address::from(0x234567890));
vm.gather();
let balance = expectedBalance;
assert!(balance.balance().if_eq(expectedBalance));
balance
}
}
fn myFunction3() -> Balance {
let tx1 = Tx::new(&[Address::from(0x123456789)], 100);
foundry_script {
vm.startBroadcast(Address::from(0x234567890));
vm.gather();
let balance = expectedBalance;
assert!(balance.balance().if_eq(expectedBalance));
balance
}
}
fn expectBalance() -> Balance {
// Returns the expected balance based on some logic (e.g. a fixed value)
Balance::new().balance()
}
}
In this script, we have three functions myFunction
, myFunction2
and myFunction3
that simulate transactions and track their balances. The error occurs when calling these functions from the foundry_script
file. Specifically, the vm.startBroadcast()
function is called with an address as a parameter, but the caller of this function does not have the same balance.
Why does this error occur?
The problem arises because foundry_script
expects the account to be in a specific state (e.g., not yet broadcasted). However, when calling these functions from foundry_script
, the caller’s address has already been broadcasted. As a result, vm.startBroadcast()
does not return an empty address, which leads to incorrect balances being tracked.
Solution: Use vm.startCall
To fix this error, we need to use vm.startCall
instead of vm.startBroadcast
. Here is the updated script:
“`rust
contract MyContract {
fn myFunction() -> Balance {
// Simulate some transactions
let tx1 = Tx::new(&[Address::from(0x123456789)], 100);
let tx2 = Tx::new(&[Address::from(0x234567890)], 200);
vm.startCall(Address::from(0x345678901))
.withArg(tx1)
.withArg(tx2)
.build().unwrap();
}
fn myFunction2() -> Balance {
let tx1 = Tx::new(&[Address::from(0x123456789)], 100);
vm.startCall(Address::from(0x234567890))
.withArg(tx1)
.build().
Leave a Reply