Aave Ape 🦍 with 🏗️ scaffold-eth 😱

This is the second post about building on Aave, see the first here (in which we develop a minimal React component).

Building ain’t easy! There comes a time when an enterprising Ethereum builder needs something that existing smart contracts can’t offer. In this article we walk through the Aave Ape 🦍 , a simple contract that lets you create and unwind leveraged positions on Aave 👻 by integrating with Uniswap 🦄, plus some testing courtesy of Hardhat👷, and of course a little 🏗️ scaffold-eth frontend.

Let’s get to it — check the code here!

🚨 This is experimental, use at your own risk! 🚨

The base: Aave + Uniswap 🧱

The Aave Ape combines two Defi protocols, Aave (for lending) and Uniswap (for swapping). Interacting with them from a smart contract requires knowing where they are (their deployed addresses) and what they look like (their interface) — see solidity-by-example. We created an to import all the relevant interfaces, and set the addresses that we need.

Interacting with Aave starts with the Lending Pool Addresses Provider — this is the source of truth for Aave V2’s latest contract addresses:

Interacting with Uniswap V2 all happens through the Uniswap Router02.

We can create a that lets us set the two addresses we need (the AddressesProvider and the Router). Once we then have the addresses and the interfaces, we can create helper functions to instantiate contracts so that we can interact with them, and fetch Aave reserve data from the . We’re ready to Ape!

The Aave Ape

inherits , so it needs to pass the same two addresses as constructor arguments, and is ready to interact with both protocols:

contract AaveApe is AaveUniswapBase {constructor(address addressesProviderAddress, address uniswapRouterAddress) AaveUniswapBase(addressesProviderAddress, uniswapRouterAddress) public {}
...

There are then two key actions of interest — and .

ape 🙈

The ape function assumes that you have collateral deposited on Aave that you are able to borrow against (not all assets can act as collateral!) Assuming you do, and you have an you want to go long and a you want to go short, this function lets a user carry out the following steps in one transaction, which they would otherwise have to do one at a time:

  • Calculate the maximum amount the user is able to borrow in the , based on their collateral (this relies on , which make the corresponding calculation)
  • Borrow that amount of from Aave V2 on behalf of the user

This requires the user to have delegated credit to the Aave Ape contract, so that it can borrow from Aave on the user’s behalf — see more about Credit Delegation here.

  • Approve the for trading on Uniswap
  • Swap the for the maximum available amount of the via Uniswap V2
  • Deposit the back into Aave on behalf of the user

The user now has long exposure to the , while they are short the , so they run the risk of liquidation if the relative value of the drops.

Some gas costs could perhaps be mitigated by pre-approving the and for all the Aave assets

The raw programmable nature of Defi is demonstrated by the additional function, which effectively lets a user re-run the function several times for the same asset pair, increasing their leverage:

// Call "ape" for the number of levers specified
for (uint i = 0; i < levers; i++) {
ape(apeAsset, borrowAsset, interestRateMode);
}

Quite a reckless to be sure!

Check the code! This function effectively reverses the , in order to close out an Ape position. The implementation is a little more complicated, as a simple reversal might not be possible (particularly if a position has been -d more than once, or if the trade has gone the wrong way!) We therefore leverage Aave’s flashloan functionality which, given an and a lets a user:

  • Borrow the amount needed to repay their debt via a flashloan from Aave V2

🧮 To repay the full debt, it is best to calculate the amount as part of the function, rather than passing an amount as a parameter, due to the constant accrual of interest

  • Repay their original debt
  • Withdraw the maximum amount of the collateral available to the borrower

🙏 The Aave Ape needs to have an allowance to transfer the borrower’s aTokens or this step will fail!

  • Swap that via Uniswap V2 for the amount owed to Aave for the flashloan (the borrow amount, plus the premium)

💵 There is a key requirement here, which is that we have enough of the deposited as collateral to repay our debt (if we don’t the transaction will revert)

  • Approve the lendingPool to reclaim the requisite amount of
  • Deposit any leftover collateral back into Aave

All in one transaction! This isn’t all happening in one place however— the function itself ends with a call to . Any call to transfers the requested assets to the specified address, then the LendingPool will make a subsequent call to the specified , in our case calling on the Aave Ape with predefined parameters. The Ape’s does a couple of things:

  1. Verify the LendingPool is the caller, and that the Ape initiated the flashloan (to protect against attacks!)
  2. Calculate the amount owed to the LendingPool
  3. Decode the params — we can use and to pass parameters from our initial function to — this gives us the information we then need in order to…
  4. Call the Ape’s function with the relevant parameters, which then does the heavy lifting described above.

And we’re out!

Hardhat testing

With 🏗️ scaffold-eth we can obviously go straight to the front-end, but while developing the Ape we also used 👷 Hardhat & Waffle to quickly check that things were working as intended, in .

Tests run on a local hardhat network, so we needed to make sure that our network in included forking:

networks: {
hardhat: {
forking: {
url: "https://eth-mainnet.alchemyapi.io/v2/<yourApiKey>"
}
},
}

We also extended the timeout in our config, as mainnet forks response can sometimes take longer than the 20 second default.

mocha: {
timeout: 80000
}

Running requires a simple:

Slow mainnet fork response time!

Testing demonstrates the actions required for the Ape to work — depositing on Aave, delegating credit, approving aTokens, and is therefore good preparation ahead of building a user interface (as well as being good practice!)

Simple frontend

It wouldn’t be a 🏗️ scaffold-eth walk-through without a simple frontend to play with, so fire up and and check it out!

deploys the Aave Ape to our local mainnet fork, passing the constructor the mainnet addresses for the Lending Pool Addresses Provider and Uniswap V2 Router— check out for the details.

  1. Send yourself some ETH with the faucet
  2. Use the Uniswap to swap it to the asset you want to deposit
  3. Deposit to Aave using

And we’re ready to go!

The top of the Ape shows your overall position on Aave (recycling the component), and the settings widget ⚙️ slides out to show more account meta-data. Then you get into the Aave Ape stuff — selecting the to go long, and the to go short.

Your local ape!

Once you have selected the asset pair you are interested in, it only remains to Delegate credit to the Aave Ape so they can borrow on your behalf, then you are ready to Go Ape!

Will you be king of the jungle?

Unwinding is similarly a two-step process — give the Aave Ape an allowance to move your aTokens, then you can unwind your position.

Note that you may not be able to Unwind if you went long an asset you hadn’t already deposited as collateral and it went against you, as you won’t have enough collateral to repay your flashloan!

The events are shown in a table below:

Better luck next time

So pretty simple stuff, but the Ape is now an end-to-end dApp!

There is lots that could be added and improved here — a better summary of your real time performance, better logic for selecting assets, including estimations of gas prices 😱 — that’s what forking is for!

Beyond localhost

While the Ape could technically go to mainnet, the price of gas⛽ and his uncouth (unaudited) nature mean that a spell on a testnet is in order. This branch has been set up to be relatively easy to deploy the Ape to Kovan, Aave’s testnet of choice…

Quick gotcha: We need to change both the Lending Pool Address Provider, and the Uniswap Router in the deployment configuration, as Aave on Kovan works with a purpose-deployed , rather than Uniswap’s own Kovan deployment address

1. Run 👼 and , and send your new deployment account some Kovan ETH

2. Deploy with the set to Kovan and the Ape will be on his way! (Deployed here!)

yarn workspace @scaffold-eth/hardhat hardhat --network kovan run scripts/deploy.js
yarn workspace @scaffold-eth/hardhat hardhat run scripts/publish.js

The app is also ready to go to Kovan, as described previously:

Update the .env file in to include a pointing at the Kovan Infura endpoint, and add

If you restart the app (CTRL-C then ), you should see a wonderful purple banner.

Vibrant.

A quick and later, and you can have an app for all to see (example here!)

Finishing up

In this post we ran through the process of creating & testing a contract leveraging Aave and Uniswap (pun intended), plus a minimal UI & the route to a testnet, all in 🏗️ scaffold-eth.

The functionality is pretty simple, and it exists elsewhere, but the goal was to illustrate how anyone can build on these Defi legos 🧱 to create interesting new experiences 🎉.

If you have feedback, questions, or if you want to collaborate on future investigatory building, please do get in touch 🐦!

And if you fancy forking & iterating, there is no shortage of possibilities…

  • Extend the ape function so that it executes the initial deposit as well as the borrow & swap
  • Let users specify the amount they want to ape or unwind
  • Update the Ape to handle multiple positions (i.e. not just single pairs)
  • Rebuild with Uniswap Flash Swaps instead of Flashloans
  • Integrate with other venues to get better pricing (1Inch, Sushiswap)
  • Estimate gas usage & better illustrate transaction costs
  • Optimise for lesser gas usage
  • Provide a better illustration of your P&L or Account Health

Or something completely different… Happy building!

References

Hat tip as always to Austin Griffith and the rest of the Buidl Guidl!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store