Continuing from Part 3, now that we have managed to deposit funds into our shared piggy bank, let's add functionality to break it.
The updated code follows - the added lines are coloured red:
pragma solidity >=0.5.0 <0.7.0;
contract SharedPiggyBank {
address payable twin1;
address payable twin2;
uint public amountPutIn;
constructor (address payable twin1address, address payable twin2address) public {
twin1 = twin1address;
twin2 = twin2address;
}
function deposit() payable public {
amountPutIn += msg.value;
}
function breakPiggyBank() public {
uint half = amountPutIn / 2;
twin1.transfer(half);
twin2.transfer(half);
}
}
We've added the function breakPiggyBank which transfers half the deposited funds (amountPutIn) to twin1, and the other half to twin2.
IMPORTANT: Before you go off and write and deploy a live smart contract, you will need to spend much more time learning about Solidity, and even various vulnerabilities.
After deploying this new code, follow these steps:
- Deposit funds into the shared piggy bank from a particular account, say 10 Ether.
- Take note of the balances of the accounts associated with twin1 and twin2.
- Press the breakPiggyBank button to initiate the associated function.
- Check the balances of twin1 and twin2 and you should notice that the balances have increased by half the amount of funds deposited into the shared piggy bank.
Great progress. But, we're not ready. Whilst anyone can deposit funds into the shared piggy bank, anyone (i.e. any account) can break the piggy bank. And that's not what we really want. We want to ensure that the piggy bank is only broken and funds sent to the twins, when both twins would like to break the piggy bank.
Let's update the code so that only a twin can try to break the piggy bank, and that it only breaks once both twins have tried to break it. The updated code follows - the added lines are coloured red, blue, green, purple and orange:
pragma solidity >=0.5.0 <0.7.0;
contract SharedPiggyBank {
address payable twin1;
address payable twin2;
uint public amountPutIn;
bool twin1brokeIt;
bool twin2brokeIt;
constructor (address payable twin1address, address payable twin2address) public {
twin1 = twin1address;
twin2 = twin2address;
}
function deposit() payable public {
amountPutIn += msg.value;
}
function breakPiggyBank() public {
require(msg.sender == twin1 || msg.sender == twin2, "Only a twin can try to break the piggy bank!");
if (msg.sender == twin1) {
twin1brokeIt = true;
}
if (msg.sender == twin2) {
twin2brokeIt = true;
}
if (!twin1brokeIt || !twin2brokeIt) {
return;
}
uint half = amountPutIn / 2;
twin1.transfer(half);
twin2.transfer(half);
}
}
The red lines define two boolean variables (which can take a value of true or false only, and are initially false). These two variables twin1brokeIt and twin2brokeIt will be used to keep track of whether twin1 and twin2 have tried to break the piggy bank respectively.
The blue line uses require, which will check if the condition input holds true. That is it will check whether msg.sender == twin1 || msg.sender == twin2 is true. msg.sender is a special keyword (globally available variable) that returns the address of the account who called this function. So, this condition is checking to make sure that the account address who called this function is either twin1 or twin2.
The green lines check if the function caller is twin1 and if so keeps track that twin1 has tried to break the piggy bank, by setting twin1brokeIt to true
Similarly, the purple lines do the same check for twin2 and keeps track if twin2 has tried to break the piggy bank, by setting twin2brokeIt to true
Finally, the orange lines are used to ensure that the piggy bank will be broken (the lines that follow the organe lines) only if both twins have tried to break it. So, the orange lines check to see if either twin1 or twin2 has not tried to break the piggy bank, and if so it exits executing further lines of code in the function by using the return statement. So, the code after these lines will only execute if both twin1brokeIt and twin2brokeIt have been set to true
Redeploy the updated smart contract, add funds to the piggy bank, and then try to break it using an account that belongs to neither twin. You should see the following in the console:
Great, so we have denied anyone who is not one of the twins to try to break the piggy bank, and provided a meaningful message back to the user.
Now try the same steps to we tried before to make sure it still allows for the twins to get their funds after trying to break the piggy bank:
- Deposit funds into the shared piggy bank from a particular account, say 10 Ether.
- Take note of the balances of the accounts associated with twin1 and twin2.
- Press the breakPiggyBank button to initiate the associated function.
- Check the balances of twin1 and twin2 and you should notice that the balances have increased by half the amount of funds deposited into the shared piggy bank.
We're getting there, but not quite there. The twins have no patience and will try to break the piggy bank immediately. Next time, we'll see how the smart contract can be implemented so that they have to wait 10 years before they can break it.