Photo by Carlos Nunez on Unsplash

The new aave ui

A peek under the hood

sakulstra
8 min readMar 18, 2022

--

In this article I want to give a deep dive into the new aave interface, the architectural decisions taken and discuss the general problems of decentralized websites and interfaces. If you’re new to aave v3 please check out the release post where you can read all about the v3 protocol improvements and new features.

Why a new interface?

The aave-ui was originally created for aave protocol V1 and continuously improved by the community and core developers to satisfy new needs(e.g. V2, staking, new governance,etc). As a result, the current codebase is dated and has frankensteined a bit over time making it hard to follow and understand the code. That said it also contains gained knowledge, workarounds and special case handling from over 2 years of development. Doing a “complete rewrite” is almost never a good idea. While the new interface looks and feels very different to the classic ui some compromises have been made to be able to maintain some chunks of the original ui and transaction logic.

On the other hand the rewrite allowed us to resolve some long outstanding issues. Let’s jump into them one by one and see if/how well we managed to resolve them. They are not in any particular order so just skip the boring parts.

Governance

Governance in the classic aave-ui — in my eyes — has always been a bit suboptimal and it has only gotten worse with each created proposal. While it was functional the ui didn’t scale well with the governance process.

Data source: In aave-ui you always have the choice between “light mode” and “normal mode”. Light mode fetches all data from rpc, whereas normal mode utilizes subgraphs for certain things to reduce rpc load and improve ui performance. To understand why this is problematic in governance one has to understand how subgraphs work and how the governance works: With the subgraph we can index events and store blockchain data when, and only when, an event occurs. In governance though some things don’t emit an event as they are not related to a transaction.
So let’s assume a proposal is created(event emitted), voted on(events emitted) — when the voting time has passed nothing happens onchain and therefore no event will be emitted. As long as no-one interacts with the proposal the subgraph will store it as active although it isn’t.

The classic ui, “solves” this issue by trying to correctly calculate current state based on potentially wrong state stored on the subgraph. The new ui “solves” this issue by ditching the subgraph. The app will now always use what was formerly known as “light mode”. We didn’t want to sacrifice on performance though so we jumped through some hoops to improve on that front as well:

Performance: In aave-ui light mode the governance will fetch all existing proposals via rpc & all related ipfs files via public ipfs gateways. This is problematic as it causes quite some load on -
a) the client
b) the rpc
c) the ipfs gateway.
This is especially problematic as these calls increase linear with each new proposal and will be kicked off per user. Also there’s no way to partially load an ipfs file, so the client has to download all proposals blobs(including description, discussion, etc) just to eventually render a list of titles.

To solve this issue we built a build cache which will hold all governance ipfs files and the current chain state of each proposal at build time. The necessary parts of the cache will then be statically inlined into the page. The page will only fetch updates by querying the diff based on the current state. As proposals are now prerendered on the server side we can now add proposal specific meta tags for rich embedding.

Styles

The classic aave-ui is using scss and styled-jsx with theme variables located in the aave-ui-kit subrepo. The issues with this setup are that:

  • the theme variables come from an aave-ui-kit subrepo which forced ui forks to fork ui-kit as well breaking the contribution loop
  • it’s really hard to follow where styles come from when just reading through a component
  • everything was custom build and there was no consistent typography or similar so it was hard to maintain by the community

The new aave-ui relies on mui which utilizes emotion for theming. Most of the new styling is now done on the theme level, so forks can simply change the theme.tsx to alter the global app styles*. All components are well tested and documented in the mui docs which decreases the learning barrier for community contributions.

*We still have to see how good this works out as all forks that I’m aware of are based on the “classic” aave-ui. We’re definitely looking forward to removing roadblocks not yet considered.

I18n

The classic aave ui hosts messages in dedicated message files and then references them via imports in the code. This is nice for type-safety and component translation isolation. But sadly, the packages to achieve this were no longer maintained and for new contributors it was hard to find* the “correct” files as text search would develiver them the messages file, not the corresponding ui file. We would have loved to use next.js native i18n solutions, but it’s not compatible with next export which is used on ipfs deployments. Therefore we went with a solution based on linguiJS which seems to be decent & well maintained.

We also added crowdin to our build pipelines to make language maintenance & language addition more seamless for non developers.

*Another thing making it hard to find files is the common, but annoying usage of index files, making file search essentially useless. So this is something we got rid off as well.

Token icons

The most common contribution to the aave-ui are token additions like most recently ENS. For a token to be added to the ui nothing has to be done as it’s all retrieved from the blockchain so it will happen automatically. The token icon is not on-chain though so it has to manually be added or the interface will look trashy. In the classic ui this is done by creating a PR at aave-ui-kit adding the token symbol as svg and another svg for the a-token variant of that icon. Once that’s reviewed and merged another pr has to be made at the aave-ui to bump the ui-kit version accordingly.

As this was quite cumbersome in the new ui you only have to drop the svg into the public folder and that’s it*. The new ui generates a-Token icons on the client only when needed. Also the token icons are no longer eagerly loaded and embedded into the main bundle reducing initial load.

*While this is sufficient for most tokens, you can still manipulate the name and similar here— this is especially useful for generic pool tokens which have a generic symbol(like G-UNI). For pool tokens the ui requires the symbol to be snake cased. If the token doesn’t follow that standard you can also rewrite the symbol.

Ipfs routing

For a React SPA to properly work you usually need some sort of server-side routing via nginx or similar. To work around that issue the classic aave ui relies on react-routers hash router which moves all routes behind a # anchor.

This kind of works, but breaks links without the # . With the nextjs file based router & static export, we managed to go back to pre-ipfs routes as each route is it’s own file and entry point.

Shareability

In the current aave-ui some urls are not actually sharable. When a link is shared with another user to to checkout the GHST token on polygon, chances are good the user will be presented with the market landing page and a different market is selected, causing the reserve to not be found. The app now persists the market in the query parameters, so v2 GHOST will actually lead the user to v2 GHOST and v3 GHOST will lead to v3 GHOST.

Dx speed

The classic aave-ui takes more than a minute for me to just boot up locally and when changing code it usually takes quite some time until it is present on the ui. There’s not a single reason for this, but more a mixture of various things (scss + postcss, custom babel, wp4, …). The new ui uses vanilla next.js with wp5 and hmr making it almost instant. We sadly had to opt out of the even faster swc option due to the dependency on babel-macro which is not yet supported.

Build time

The classic aave-ui takes around 10 minutes to build & deploy. The new interface takes around 50% less time while at the same time building more than 60 static pages for governance which the classic ui doesn’t. There’s probably still some room to improve though(e.g. swc once macro is supported).

Bundle size

This point in my eyes is the most interesting & also saddest point. The classic aave-ui has an initial js bundle load of 2.2MB. The goal was to come close to 400kb, but this was not achieved. In the end we’re at around 480kb for the main bundle but around 560kb with the page & framework bundle. One reason for the bundle-size getting out of hand was the lack of monitoring. In the new aave interface there’s a ci step running on each commit comparing bundle size with master to add transparency to dependency updates & feature additions.

Some will say that React was the wrong choice when aiming for a good bundle size and they are correct. React was chosen because it allowed us to reuse some of the classic ui; also because the ecosystem is huge and the people involved being more comfortable with it.
We would be happy to review a PR which switches to From React to Preact or review an alternative ui being built on svelte or something similar. That said, React is not the(only) reason for the immense bundle size — a huge part of that is caused by the broader “web3” ecosystem. We started opening issues/PRs at certain dependencies for much needed changes, but eventually we dropped some wallet integrations where we didn’t think we’re expected to see improvements in the near future.
Eventually a big issue that remained is the n different libraries for handling big numbers and the m different versions of these libraries requested by each wallet integration. Sadly the bundle still includes 10 different copies of bn.js (bignumber handling is around ~20–25% of total bundle size :/). On the bright side, the governance pages might drop a few kb in the near future.

I hope you enjoyed reading this ❤
If you feel you can make things better don’t hesitate to create an issue or pr on github. Even if you don’t feel like it — give it a go!
🏗 💪 🌈 !

--

--