DatingDapp

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

Missing Balance Validation Allows Overdraft Transactions

Root + Impact

Description

  • Describe the normal behavior in one or more sentences


  • Explain the specific issue or problem in one or more sentences

  • The contract does not validate that sufficient balance exists when creating or executing transactions. Users can create and approve transactions for amounts exceeding the wallet balance

Risk

Likelihood:

  • Reason 1 // Describe WHEN this will occur (avoid using "if" statements)

  • Reason 2

Impact://

  • Impact 1

  • Wasted gas on approvals for impossible transactions

  • Transaction array bloat with failed transactions

  • Poor user experience

  • Impact 2

Proof of Concept

// Wallet has 1 ETH
MultiSigWallet wallet = new MultiSigWallet(owner1, owner2);
payable(address(wallet)).transfer(1 ether);
// Owner1 creates transaction for 10 ETH
vm.prank(owner1);
wallet.submitTransaction(recipient, 10 ether); // No revert!
// Both owners approve
vm.prank(owner1);
wallet.approveTransaction(0);
vm.prank(owner2);
wallet.approveTransaction(0);
// Execution fails, but transaction marked executed = true
vm.prank(owner1);
vm.expectRevert("Transaction failed");
wallet.executeTransaction(0);
// Transaction is now in limbo - executed=true

Recommended Mitigation

- remove this code
+ add this code
function submitTransaction(address _to, uint256 _value) external onlyOwners {
if (_to == address(0)) revert InvalidRecipient();
if (_value == 0) revert InvalidAmount();
// ✅ Validate balance at submission
require(_value <= address(this).balance, "Insufficient balance");
transactions.push(Transaction(_to, _value, false, false, false));
uint256 txId = transactions.length - 1;
emit TransactionCreated(txId, _to, _value);
}
function executeTransaction(uint256 _txId) external onlyOwners nonReentrant {
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");
// ✅ Revalidate balance at execution (in case of other txns)
require(txn.value <= address(this).balance, "Insufficient balance");
txn.executed = true;
(bool success,) = payable(txn.to).call{value: txn.value}("");
require(success, "Transfer failed");
emit TransactionExecuted(_txId, txn.to, txn.value);
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 2 hours 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!