Sending funds from a contract
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the Million Ether Homepage course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Million Ether Homepage, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
[00:00 - 00:09] Now we're trying something new. We want a contract to send funds to another address. And before we get started, I want to point out we're entering a danger zone.
[00:10 - 00:30] What's the worst thing that can happen to your smart contracts? The worst thing is we're to have a bug that causes people to lose money in unintended ways. Because sending funds is such a major part of smart contracts, solidity and ethereum have a number of ways to send value around. The problem is this flexibility means that bugs can be introduced in subtle ways.
[00:31 - 01:27] Since this is the first time we've talked about contracts sending funds, I want to focus on the high level ideas. But do not release code in production that handles real funds until we've had time to talk through the other security pitfalls. For example, we haven't talked about re-entrance yet, nor have we discussed fallback functions or contracts calling other contracts. We will. But I want to make the point that this video teaches you enough solidity to be dangerous. And we need to talk more about the implication of contract sending funds before you release a production app. Okay, with that out of the way, let's get back to our bank example. In this contract, we accepted deposits, but we didn't keep track of them. The only way to get the money back out of the bank was to destroy the contract and send the money back to the contract owner. Let's fix this. We'll start by adding a new property to the bank called balances, which will be a mapping that keeps track of how much ether was sent by which address.
[01:28 - 01:59] Think of it as keeping track of different bank accounts, say mapping from an address to a U-int and its public to list the balances. This property has a key, which is a particular address and a value, which is the amount of funds designated for that address. When someone makes a deposit, we want to credit their account balance. So let's add this line to the deposit function. Balance is, for that sender, increment by the message value. And note that, because this is an unsigned integer, we should be checking for overflows. But we'll talk about safe math later.
[02:00 - 02:10] This will add the message.value amount to the current balance for this address. Keep in mind that this balance's property is internal logic for keeping track of the balance for each address.
[02:11 - 03:10] That is, the contract itself has one account balance. That is, the true Ethereum network recognized total balance owned by this contract. This logic keeping track of account balances is totally internal bookkeeping. We could set these balances to whatever we want, and it doesn't directly affect the true amount of ether that the contract controls. The contract holds a total amount of real ether, and this balance is mapping is just for our contract's internal bookkeeping. Try putting this script into remix and play around with the deposit function and confirm for yourself that it works. To write our withdrawal function, how do we actually send funds from our contract to another address? There are several solidity constructs for sending funds. They have differing semantics, and we need to be very careful about which we choose. The two that we'll talk about right now are dot send and dot transfer.
[03:11 - 04:01] We use dot send like this. Given an address, we call dot send on that address, and we send an amount. If dot send fails, it will return false, not revert changes. This means we need to check the return value of dot send every time we use it. So every time you use dot send, it should look like this. If the negation of calling some address dot send is true, then handle the failure by reverting the necessary changes. Dot transfer is a high-level version of dot send that will revert changes if dot send fails. That is, dot transfer is equivalent to if send fails , revert changes. This is similar to throwing an exception, and remember that if dot transfer fails, all state changes will be reverted, and the function will exit. But there's a question, Why would sending funds to another address fail?