# Vending Machine
For this challenge, you have to deal only with a single Smart Contract called VendingMachine, a simple contract that models after a vending machine that provides only peanuts At deployment time the contract is funded with some ether and your goal is to drain it from the whole balance.
HINT: Focus on the withdrawal function 😃
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
contract VendingMachine {
address public owner;
uint256 private reserve;
bool private txCheckLock;
mapping(address => uint256) public peanuts;
mapping(address => uint256) public consumersDeposit;
constructor(address player) payable {
require(
msg.value >= 1 gwei,
"You need a minimum of reserve of 1 gwei before deploying the contract"
);
owner = player;
reserve = msg.value;
peanuts[address(this)] = 2000;
txCheckLock = false;
}
function isExtContract(address _addr) private view returns (bool) {
uint32 _codeSize;
assembly {
_codeSize := extcodesize(_addr)
}
return (_codeSize > 0 || _addr != tx.origin);
}
modifier isStillValid() {
require(!txCheckLock, "Sorry, this product project has been hacked");
_;
}
modifier onlyOwner() {
require(msg.sender == owner, "Ownable: caller is not the owner");
_;
}
function getPeanutsBalance() public view returns (uint256) {
return peanuts[address(this)];
}
function getMyBalance() public view returns (uint256) {
return consumersDeposit[msg.sender];
}
function getContractBalance() public view returns (uint256) {
return address(this).balance;
}
function getReserveAmount() public view onlyOwner returns (uint256) {
return reserve;
}
function deposit() public payable isStillValid {
require(
msg.value >= 0.1 gwei,
"You must have at least 0.1 gwei to initiate transaction"
);
consumersDeposit[msg.sender] += msg.value;
}
function getPeanuts(uint256 units) public isStillValid {
require(
consumersDeposit[msg.sender] >= units * 0.1 gwei,
"You must pay at least 0.1 gwei per peanutToken"
);
require(
peanuts[address(this)] >= units,
"Not enough peanuts to fulfill the purchase request"
);
consumersDeposit[msg.sender] -= units * 0.1 gwei; // Debits caller's deposit
peanuts[address(this)] -= units; // Reduce the amount purchased from the peanuts stock
peanuts[msg.sender] += units; // Credits the caller with amount of peanuts purchased
}
function withdrawal() public isStillValid {
uint256 contractBalanceBeforeTX = getContractBalance();
uint256 balance = consumersDeposit[msg.sender];
uint256 finalContractBalance = contractBalanceBeforeTX - balance;
require(balance > 0, "Insufficient balance");
(bool sent, ) = msg.sender.call{value: balance}("");
require(sent, "Failed to send ether");
consumersDeposit[msg.sender] = 0;
uint256 contractBalanceAfterTX = getContractBalance();
if (
(contractBalanceAfterTX < finalContractBalance) &&
isExtContract(msg.sender)
) {
txCheckLock = true;
}
}
function restockPeanuts(uint256 _restockAmount) public onlyOwner {
peanuts[address(this)] += _restockAmount;
}
function hasNotBeenHacked() public view returns (bool) {
return !txCheckLock;
}
}
← SafeNFT