DatingDapp

AI First Flight #6
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

LOW-01 — executeTransaction does not check contract balance

LOW-01 — executeTransaction does not check contract balance

Description

  • executeTransaction attempts to send txn.value ETH without first verifying the contract holds sufficient balance. The transaction will revert at the .call level, but the error message is generic and misleading — "Transaction failed" gives no indication that the cause is insufficient funds.

function executeTransaction(uint256 _txId) external onlyOwners {
// @> no balance check before transfer
(bool success,) = payable(txn.to).call{value: txn.value}("");
require(success, "Transaction failed");
}

Risk

Likelihood:

  • Occurs whenever submitTransaction is called with a _value greater than the contract's current ETH balance

Impact:executeTransaction reverts with a generic "Transaction failed" message giving no indication that insufficient balance is the cause

Proof of Concept

function test_executeRevertsOnInsufficientBalance() public {
// Deploy MultiSig with Alice and Bob as owners
// Simulate it receiving only 0.5 ETH at deployment
MultiSigWallet wallet = new MultiSigWallet(alice, bob);
vm.deal(address(wallet), 0.5 ether);
// Alice submits a transaction for 1 ETH (more than contract holds)
vm.prank(alice);
wallet.submitTransaction(alice, 1 ether);
// Both owners approve - wasting gas with no warning
vm.prank(alice);
wallet.approveTransaction(0);
vm.prank(bob);
wallet.approveTransaction(0);
// Execute reverts - but error says "Transaction failed"
// No indication that the cause is insufficient balance
vm.prank(alice);
vm.expectRevert("Transaction failed");
wallet.executeTransaction(0);
// Funds are stuck - no withdraw mechanism exists
assertEq(address(wallet).balance, 0.5 ether); // still locked
}

Recommended Mitigation

function executeTransaction(uint256 _txId) external onlyOwners {
require(_txId < transactions.length, "Invalid transaction ID");
Transaction storage txn = transactions[_txId];
require(!txn.executed, "Transaction already executed");
require(txn.approvedByOwner1 && txn.approvedByOwner2, "Not enough approvals");
+ require(address(this).balance >= txn.value, "Insufficient contract balance");
txn.executed = true;
(bool success,) = payable(txn.to).call{value: txn.value}("");
require(success, "Transaction failed");
emit TransactionExecuted(_txId, txn.to, txn.value);
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 8 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!