By Pedro Bergamini and Coogan Brennan
In the first installment of this series, we’re going to explain some of the underlying concepts behind flash loans and flash swaps. In part two, we’ll show you how to build your own Ethereum bot, running on Infura, watching for and executing profitable arbitrage opportunities using flash loans.
Arbitrage trading, independent of flash loans or blockchain, is when you have the same asset with two different prices in two different exchanges.
For example, let’s look at two exchanges: Uniswap and Sushiswap. Sushiswap is a fork of Uniswap, which means they run on the same contract code. While they’re two different exchanges, we can use the same code to execute the same trade. Also, since Sushiswap is a newer exchange, there may be fewer bots written for it.
Arbitrage works like this: One ether is worth 80 Dai on Uniswap and 100 Dai on Sushiswap. We purchase 1 ETH on Uniswap and then immediately sell it on Sushiswap, for a profit of 20 Dai (minus gas and fees). This is a typical, profitable arbitrage trade.
Flash Loan vs Flash Swap
Flash loans and flash swaps are concepts specific to blockchain. The diagram above shows some key differences between the two. Let’s flesh these points out.
Flash loans have a 0.09% fee on the interest-generating protocol Aave. It requires a minimum of three operations: 1) borrow on Aave, 2) swap on a decentralized exchange, and 3) arbitrage swap on another decentralized exchange to realize profit. Flash loans must be paid back in the same asset you borrowed. If you borrow Dai, you need to pay your loan back in Dai.
Flash swaps allow traders to receive assets and use them elsewhere before paying for (or returning) them later in the transaction. Flash swaps, as done on Uniswap, don’t have flat fees (yet) but rather take a swap fee. This can be seen as a “free” loan compared to a flash loan because the swap fee is taken out of the trading order- we do not have to make a separate payment. Last point of difference: we can pay back flash swaps in either asset we’re exchanging. If we use a flash swap to buy Dai with ETH, we can pay the swap back in either Dai or ETH. This allows us to do more sophisticated operations.
Flash swaps and loans both employ “optimistic transfer,” a fascinating technique we’ll get into later.
Flash Loans and Contracts
Another concept to understand about flash loans is the nature of Ethereum transactions. All Ethereum transactions originate from an Externally Owned Account (EOA), which is an Ethereum address operated by a human. An Ethereum transaction can go from one EOA to another EOA, like when you pay a friend. An Ethereum transaction can also go from an EOA to execute code in a contract. That contract can call another contract and so on, until the gas in your transaction runs out.
*Note: If you’re new to transactions in Ethereum, check out this helpful introduction to accounts, contracts, and types of Ethereum transactions.
We will see later that flash loans require multiple function calls within their execution, something that’s not possible from an EOA. Instead, we will deploy a contract that contains the multi-step process. We initiate the arbitrage from our EOA to the Aave contract but all we provide is the address to our deployed contract. We also need to provide enough ETH to cover the gas cost of the transaction, which can be quite costly due to the complexity of the transactions. (Remember, a transaction’s price is determined by how much computational power it requires).
Both flash loans and flash swaps employ a technique called optimistic transfer. This remarkable DeFi innovation allows a user to take uncollateralized loans or swaps and execute a trade as long as the user pays the service back by the end of the trade. To better understand this mind-bender, let’s take a look at some code.
Here is the LendingPool.sol contract code from Aave (V1). We’re looking at the
flashLoan function, specifically the following methods:
In line 877, we can see the contract transfer funds to the user’s contract “optimistically”—It doesn’t check the balance of the user’s contract to see if they have enough of that asset. Instead, the contract simply transfers the amount.
How is this possible? Won’t the user just run off with those tokens? Well, if this was the end of the transaction then that would be a serious problem. But as you can see, it’s not the end of the code. Whether the user’s contract keeps those tokens is contingent on the next few lines successfully executing.
After the optimistic transfer, on line 881, we see the Aave contract then calls the user’s contract with the optimistic balance of tokens and any parameters the user has passed in. Those parameters will be whatever the user needs to pass on to their contract for the trade to be successfully executed. The transaction workflow now temporarily halts on the Aave contract and moves to the user’s contract, which executes its logic and hopefully a successful trade.
By line 884, the user’s contract has executed their code and the workflow now returns to the Aave contract, which has a
require statement extracting the fee from the user’s contract. The optimism is over and now we must see if the contract has executed a profitable trade! If so, the Aave contract will be able to deduct its fee. If the trade has not been profitable, this
require statement will fail which means the entire transaction fails, meaning the asset transfer we conducted optimistically two steps before essentially never happened.
Let’s take a look at how Uniswap implements their optimistic transfer. This is from their UniswapV2Pair.sol contract, specifically the
The optimistic transfer happens at line 170-171, it’s the
_safeTransfer method. Uniswap has even commented out the optimistic transfer to better identify it (Uniswap has great documentation and educational materials about their protocol contracts, by the way!). The next line is the Uniswap contract calling the user’s contract with the optimistic balance.
Again, imagine the transaction workflow temporarily pauses on the Uniswap contract and moves to the user’s contract with the tokens optimistically transferred. Once the execution has finished on the user’s contract, the transaction workflow comes back to the Uniswap contract. The Uniswap contract then assigns the new balance of the user’s contract and attempts to take the swap fee (lines 180-181).
If the user’s contract had failed to make a profit with the tokens, the
require statement on 182 would fail and the entire transaction would revert. This is the key to optimistic transfer—it’s 100% dependent on the trade being successful. If it’s unsuccessful, the transaction is invalid and will revert to the state before the tokens were transferred. If it’s successful, however, the optimistic transfer is maintained and the user takes their profit.
Arbitrage, contract coding and optimistic transfer come together to create an impressive new tool. It’s an innovation built on top of the innovation of public blockchains. The two innovations compound each other, creating a truly powerful and unique mechanism.
In part two of our series, the theoretical will meet the practical. We’ll walk through actually building an arbitrage bot. You can preview the code here.
→ Our Eth2 API is live on mainnet! Drop us a message for Beta access.
→ Join the waitlist for Infura’s Filecoin API.
→ Submit a request for access to Infura Transactions.