100 Days of Web3 (Days 51-60)

I spent a large part of days 51-60 learning more about the Maker protocol and Foundry. Although I still can’t say that I know every detail of the Maker protocol, I now have a much better understanding of it. It’s definitely gratifying to improve my knowledge of one of the biggest DeFi protocols. It was also great to get some experience with Foundry, which is a very effective toolkit for developing smart contracts.

Day 51

I continued my exploration of the Maker protocol source code. In particular, I reviewed the dog contract which is responsible for liquidating vaults with an unhealthy collateral to debt ratio. The dog contract will confiscate the collateral of the unsafe vault by transferring it to another contract known as the clipper. The dog contract also sets limits for the total amount of debt being auctioned, including a limit per collateral type as well as a global limit.

Day 52

The next contract I looked at was the clipper contract. This contract controls the collateral auction mechanism. It is called by the dog contract to initiate an auction. The starter of the auction, known as the keeper is given a Dai reward consisting of a fixed reward as well as a percentage of the debt being auctioned.

The collateral auctions are Dutch-style auctions where the price of the collateral goes down over time. When a user bids on on the collateral it is actually an instant buy, which is different from traditional English-style auctions. The clipper contract has configuration settings which control the maximum duration of an auction and the minimum selling price of the collateral. If either of these conditions are reached, then the auction must be restarted.

Day 53

The price of collateral goes down as the collateral auction progresses. The rate at which the price decreases is determined by the abacus contract. The clipper contract is thus dependent on the abacus contract. There are many different implementations of the abacus contract such as the LinearDecrease contract in which the price of the collateral decreases linearly. There are also other implementations including ones which decrease the price exponentially.

Day 54

Next, I went through the stability module of the Maker protocol, which consists of the flapper, flopper and vow contracts. The flapper contract is used for surplus auctions. When the surplus Dai contained by the Maker protocol exceeds a certain threshold, that Dai is auctioned off. Users bid increasing amounts of Maker token in order to get that surplus Dai. Once the surplus auction is complete, the Maker tokens paid by the winning user are burned, thus decreasing the supply of the Maker token.

The flopper contract is used for debt auctions, which are the opposite of surplus auctions. When the excess debt in the Maker protocol reaches a certain threshold, Maker tokens are minted and auctioned off for Dai. The Dai tokens which users contribute during the auction are burned, thus reducing the excess debt in the system.

Day 55

I then looked at the rates module of the Maker protocol which consists of the jug and pot contracts. The jug contract is responsible for updating the rate of the collateral type within the vat contract. This rate represents the the stability fee charged by the Maker protocol for borrowing Dai. The way the rate is calculated is mathematically interesting because it involves multiplying a number by the current rate for each second that has passed.

The pot module controls the Dai savings rate functionality which allows users to lock their Dai into a contract and earn a yield over time. The mathematics of the Dai savings rate are very similar to how the stability fees on vaults are calculated.

Day 56

While learning about the Maker protocol and dapp.tools, I heard about Foundry, which is a rewrite of the dapp.tools functionality. After reading about it, I decided to give a try by going through the Foundry book. I really like Foundry as it seems like a faster and more user-friendly version of dapp.tools. I suspect Foundry will really grow in popularity as it develops further.

Day 57

Despite having spent several days going over the source code of the Maker protocol, I still felt that I didn’t understand it that well. I decided to implement a simplified version of the protocol using Foundry. I decided to design the implementation differently by using inheritance, libraries and more intuitive naming.

I started by implementing an Auth contract from which many other contracts would inherit. This contract simply implements a modifier for use with functions which can only be called by approved addresses. I also created the contract for the Dai token by leveraging the OpenZeppelin contracts library. In addition, I used GitHub Actions for the first time with a simple workflow which would compile the contracts and run tests.

Day 58

Next, I implemented a Delegate contract which allows users to let others perform actions on their behalf. I created a simplified version of the vat contract called Vaults, which inherited from the Delegate contract. I kept the Vaults contract simple and left out details such as debt ceilings and floors. I also created a small Solidity library with mathematical functions taken from the Maker protocol for performing operations with both unsigned and signed integers.

I wrote many tests for the Vault contract, and made good use of Foundry’s cheatcodes feature. The Foundry cheatcodes allowed me to make calls to contracts from multiple users and also to assert when methods fail with specific error messages.

Day 59

I then created my own version of the Maker join contracts which I called TokenBridge and DaiBridge. The implementation of these was almost identical to the official Maker contracts. However, I split the code up by creating an abstract base contract called Bridge. Both the TokenBridge and the DaiBridge inherited from the Bridge contract.

Day 60

I wrote tests for the TokenBridge and DaiBridge contracts. I used the expectEmit cheatcode from Foundry to verify that the correct events were being emitted. I also added a more extensive test for the Vaults contract in which a user performs the following sequence:

  1. Adds tokens into the protocol through the TokenBridge contract.
  2. Opens a vault using a method on the Vaults contract.
  3. Mints Dai using the DaiBridge contract.
  4. Pays back the Dai using the DaiBridge contract.
  5. Closes the vault
  6. Withdraws the tokens from the protocol through the TokenBridge contract.

Summary

I’m hoping to finish up my reimplementation of the Maker protocol in the next few days. Then, I’d really like to explore layer 2 solutions including optimistic rollups such as Optimism and Arbitrum as well as zk-rollups. I’d also like to try developing for non-EVM chains such as Solana sometime soon.