Not sure if you guys have already seen, but the issue has now been fixed, and we can now set values to zero and use the delete operator in Remix without running out of gas
I’ve tested it, and it now works fine. The issue that was opened in the Remix Project’s repository in GitHub also now confirms that it’s been fixed and the issue is now closed…
Just following up, as promised, after doing some testing …
This is correct… And it’s also worth emphasising that, with a fixed-size array, you will obviously only retrieve one of the zero values I listed, if you reference an index position which is less than the pre-defined fixed size e.g. If the fixed-size array uint[3] balances has not yet had any values assigned to it, then referencing: balances[0] , balances[1] and balances[2] will all return zero; but balances[3] will result in an error.
This is correct
Yes you can … this works in exactly the same way as with a fixed-size array.
This is correct.
Yes, you are right, they are related…
Removing a struct instance from an array using the delete operator is equivalent to assigning a zero value to each of its properties (according to their data types).
You can also use the delete operator on individual properties of a specific struct instance (whether stored in an array or mapping, or not). This will set that property’s value to a zero value, but it will not affect any of the values stored in the other properties of that struct instance.
I hope that clarifies things, and ties up any loose ends. Just let me know if you have any other questions
require(balance[msg.sender] >= amount, “Withdraw amount must be equal to or less than balance amount”);
balance[msg.sender] -= amount;
msg.sender.transfer(amount);
}
Check the amount the sender is requesting to withdraw is less or equal to the balance within the contract; then if so
after the withdrawal reduce the senders balance by the withdrawal amount, then
assert that the previous balance is now the same as the previous balance less the amount withdrawn
function withdraw(uint amount) public returns (uint){
// check balance of address in contract in less or equal to the withdraw amount
require(balance[msg.sender] >= amount);
// execute the withdral
msg.sender.transfer(amount);
// reduce the balance of the address in the contract by the withdraw amount
balance[msg.sender] -= amount;
// check that the balance of the address has been reduced by the withdraw amount
uint previousSenderBalance = balance[msg.sender];
assert(balance[msg.sender]== previousSenderBalance - amount);
}
Your function is OK, but the order of the variables is not entirely correct, you are transfering before chaing the value and fetching the previous value after sending the funds.
It should be like this
function withdraw(uint amount) public returns (uint){
// check balance of address in contract in less or equal to the withdraw amount
require(balance[msg.sender] >= amount);
// check that the balance of the address has been reduced by the withdraw amount
uint previousSenderBalance = balance[msg.sender];
// reduce the balance of the address in the contract by the withdraw amount
balance[msg.sender] -= amount;
// execute the withdral
msg.sender.transfer(amount);
assert(balance[msg.sender]== previousSenderBalance - amount);
}
indeed, also the assertion is a nice feature to validate the entire process made before finishing the function execution.
Also its nice to decrease the balance of the user before transferring in case of reentrancy attacks, not an entire solution for it, but a nice first step. (check the ethereum security course for more info on reentrancy attack)
pragma solidity 0.8.7;
contract Bank {
mapping(address => uint) balances;
address owner;
event balanceUpdated(uint prevBalance,uint newBalance, address indexed updatedAccount);
modifier onlyOwner {
require(msg.sender == owner,"Only SC Owner can Call this");
//run the real functions, Practically EVM will replace all of function statement here
_;
}
modifier sufficientBalance(uint _amount){
require(balances[msg.sender] >= _amount,"Balance Not Sufficient");
_;
}
constructor(){
//here owner becomes the creator of SC
//mostly useful for restricting function access to admins
owner = msg.sender;
}
// admin function can only be perfromed by the owner of SC
//payable allows receiving money from the caller of the function
//the msg.value will get added to the balance of the SC
//the internal balance data structure allows keeping track of who this money is owed to
function deposit() public payable returns(uint){
uint prevBalance = balances[msg.sender];
balances[msg.sender] += msg.value;
//emit log
emit balanceUpdated(prevBalance, balances[msg.sender], msg.sender);
return balances[msg.sender];
}
function withdraw(uint amount) public sufficientBalance(amount) returns(uint){
//we can have other addressess
//address payable _toAddress = 0x617F2E2fD72FD9D5503197092aC168c91465E7f2;
//_toAddress.transfer(amount);
//this will send amount(in ether) from SC to msg.sender
//since balances are internally Manager within SC,
//Condition should be checked if msg.sender balance is enoough
//else it will transfer from SC which is cumulative of all users
//sufficient balance, commented as using modifier
//require(balances[msg.sender] >= amount,"Balance Not Sufficient");
balances[msg.sender] -= amount;
payable(msg.sender).transfer(amount);
//emit log
emit balanceUpdated(balances[msg.sender]+amount, balances[msg.sender], msg.sender);
return amount;
}
function getBalance() public view returns(uint){
return balances[msg.sender];
}
}