Author: Anıl Helvacı

Date: 2022-08-15

Pool Based Lending Protocol On Agoric

As BytePitch we have a considerable amount of work resource allocated for blockchain development ranging from a variety of frameworks. In this article we will go over a lending protocol we built on Agoric.

Introduction: What is Agoric?

Agoric is one of the platforms that BytePitch is building on. Agoric lives on the Cosmos network and has the capability to communicate with other Cosmos networks via IBC(Inter-Blockchain Communication) protocol.

How does Agoric work and what it brings to the table?

What's innovative about Agoric is that it aims to bring over 10 Million JavaScript developers out there to DeFi space. DeFi space has a lot of protocols/apps yet to be built to meet the market demand and bring the true power of blockchain to real life. Agoric plans to solve this problem by drawing JavaScript community to smart-contract development. However, in the mean time it doesn't let go the security aspect of blockchain technology which is so crucial to the decentralized applications. So Agoric introduced its own framework of JavaScript. This framework consists of four main parts;

  • Hardened JavaScript

  • Eventual send with E()

  • Far(), Remotable and Marshaling

  • Notifiers and Subscriptions

There's also a concept worth mentioning which is the VAT. VAT is a piece of software that has its own message queue, a call stack of frames, and a heap of objects, much like the event loop concurrency model in web browsers and Node.js. In the Agoric VM (also called as

ag-solo
), there are multiple vats. VATs help us to isolate processes and enforce object-capabilities. Object-capabilities is an important part of Hardened JavaScript and also is a main component of the Agoric security model. For more in depth information about how Agoric achieves distributed secure JavaScript programming, please check out the official docs on the Agoric JavaScript Framework.


Context

Lending and borrowing have always been one of the most crucial parts of world economy. Until now, banks have been the main institutions who took on this job. With the development of Web3 and blockchain technologies gaining more and more power, we now do not have to rely on banks to evaluate us as "low-risk" and provide us with the liquidity we need.

Enter Compound Finance

Compound Finance is one of the first protocols to successfully implement a pool based lending protocol. It lives on Ethereum network and currently has almost $4 billion locked into it and lent almost $1 billion.

The numbers above are correct at the time of writing this article and probably will change later.

How does Compound Finance work?

In Compound Finance users can either supply liquidity to one of the pools or they can borrow some asset from one of the pools.

Supply Assets

Users supply an asset to one of the existing pool and receive a cToken in return. For instance, if you supply ETH to the ETH pool you receive cETH in return. You can use this cETH to redeem your underlying, meaning ETH, assets later. There's an exchange rate between the underlying asset and the protocol asset in each pool, we'll cover that in detail later in this article.

There are two main incentives for supplying liquidity to the protocol;

  • Earning Interest: Users earn interest per block. The longer the liquidity stays the more money users will make.

  • COMP
    Governance Token: COMP is the official governance token for Compound protocol. Users receive these tokens as they interact with the protocol. Thus, when a user supplies an asset to one of the pools they earn COMP tokens as well. COMP token is listed on many of the markets so users can turn them into some other asset. Also they can choose to hold their COMP tokens and vote on governance proposals. Participating in another liquidity mining protocol and earning rewards might be an option too.

Borrow Assets

Borrowing an asset from one of the pools is another essential part of Compound Finance. The main difference between borrowing from a decentralized protocol instead of a traditional bank is that decentralized protocols do not ask questions like below before they lend you the money;

  • Who are you?

  • How old are you?

  • Where do you live

  • Are you married?

  • Do you have children?

  • What do you do for living?

  • How much do you make a year?

  • Have you been working in your last job longer than one year?

  • Did you pay your prior debts?

......

We can extend the list but you get the idea. The banks ask these questions in order to evaluate you'll pay your debt or not. So it's a matter of risk calculation, if people do not pay their debts institutions who gave them the money will go bankrupt. There's quote that explains this situation very well, I believe:

"At some point a debt is a problem of the ones who lend the money not the ones who borrow it."

So how does decentralized lending protocols like Compound not go bankrupt? How do they get away with lending money to everyone whoever is willing to pay the interest?

The answer is: Over-collateralization. There are two types of collateralization strategies when it comes to lending money;

  1. Under-collateralization: The word 'under' means that value of the collateral requested from the borrower is less than the value of the actual debt. Say if you are to borrow $100 and the strategy is under-collateralization with %30 collateralization factor, it means that you should give away $30 of collateral before you borrow money. This strategy is like the more traditional one compared to the other one.

  2. Over-collateralization: The word 'over' means that the value of collateral should be higher than the value of debt. For instance, if you have $100 to use as collateral and the collateralization factor is %80 then you can borrow $80 at most. The main idea is to secure the lender in a way that even if the borrower doesn't pay their debt, the lender does not lose money.

Relationship Between Over-Collateralized Debt and Liquidation

There's one important concept that we should mention if we're talking about over-collateralization and that is liquidation. In this context liquidation refers to the action of turning the collateral at hand into the debt has been given away. Liquidation is the point where the lender is sure that the borrower won't pay their debt and takes action to secure their money given away as debt.

An Example

Think of it like this, in the earlier example we said that there's $100 as collateral and max value of debt is $80. Say the borrower borrowed $78 worth of some asset as debt. This is a dangerous situation because the liquidation will occur as soon as the value of debt exceeds $80. Let's imagine we have a very irresponsible borrower and they refuse to pay their debt. As interest accrues on the principal debt, it is for sure that at some point the value of debt will reach the liquidation limit which is $80(max debt). The borrower insists on not paying the debt and the value of debt reaches to $80. At this point the lending protocol initiates liquidation and sells the collateral in order to cover the value of debt. Once the collateral is sold, the borrower has no debt left and their loan is closed. There are other possibilities that might trigger liquidation but here we just wanted to talk about the process.

Several Strategies To Sell The Collateral
  • Sell the collateral in an Automated Market Maker(AMM)

  • Sell the collateral yourself with a slightly lower price than the market price and expect people to take advantage of this opportunity

Compound uses the later strategy in order to pursue full decentralization but we'll use the first one in our protocol since Agoric has its own native AMM.

Dynamic Rates

One other cool feature of Compound Finance is that its rates, whether it is the exchange rate between the underlying asset and the cToken or the interest rate charged on every debt, are dynamic. Meaning they change in response to current market situation. This is good because it enables the market to balance itself and not run out of liquidity.

For example, let's say there's $1000 of some underlying asset in a pool and also $100 of total debt lended out there. At this point of the market let's also say the annual interest rate applied to loans is %x. If someone borrows $50 more now the current market state is changed to, $950 of underlying asset liquidity and $150 total debt out there. So, for the sake of dynamic interest rate new annual interest rate is now %y and we are sure that

y > x 
because the underlying liquidity is now less than what it was so the price of money, interest rate, is now increased.

There are three important rates for Compound protocol;

  • Utilization Ratio

  • Borrow Rate

  • Exchange Rate

Below are the formulas for those rates;

Utilization Ratio

Utilization Ratio

Borrow Rate

Borrow Rate

Exchange Rate

Exchange Rate

You can take a look at the markets listed in the Compound protocol if you wish to see how these variables are used in real life.

You can check the Compound Whitepaper for more information.

For the implementation you can see Compound Protocol Repository on GitHub.


Pool Based Lending Protocol On Agoric

After some context we are now ready to talk about our version of a pool based lending protocol. Before we dive in you'll need some prerequisites in place;

Prerequisites

  • ERTP: Agoric's interpretation of digital assets, or tokens.

  • Zoe: Agoric's Smart contract development framework. Protects users' assets from bugs and malicious developers.

  • Agoric Offers: Basic logic used when interacting with contracts.

  • Agoric Native AMM: An Automated Market Maker where you can trade various tokens whether they're native Agoric tokens or tokens belong to some other network and imported via IBC.

  • PriceAuthority: An interface between Zoe and price oracles.

You might also want to check out this documentation guide to have roadmap for more all around information.

Overview

The complete code for this protocol can be found in this repo. Essentially, a user is able to do five main operations in our protocol;

  • Deposit Money

  • Borrow Money

  • Redeem Deposited Money

  • Adjust Loan

  • Close Loan

Functionality for these operations is distributed among multiple components. An high level overview of protocol components can be found below.

Component Diagram - Lending Protocol
LendingPool

Entry point to the protocol. Points users to the correct pools after doing necessary checks. See the code.

PoolManager

PoolManagers are identified by their underlying assets. If there's a token called VAN and we decide add a pool for that token to our protocol, we refer to that pool as 'VAN Pool'. A PoolManager is where the actual underlying assets are stored and protocol tokens are minted. Our VAN Pool mints a protocol token called 'AgVAN' on every deposit transaction and hands this protocol token to the user in return to their underlying asset. PoolManagers charge interest on the underlying asset they lended. This is where the actual

deposit, borrow and redeem
operations happen. See the code.

PriceManager

A hub containing the price authorities this protocol uses. Since we depend heavily on price authorities and the number of price authorities we need is a lot, it makes sense to manage all price authorities in a wrapper. See the code.

ProtocolMath

The module we implement the formulas for

exchangeRate, utilizationRatio and borrowRate. 
See the code.
 

DebtsPerCollateral

Our pools accept multiple types of protocol tokens as collateral. In order to group loans with the same collateral type and same debt type we use this module since they'll behave similarly in response to changes in the market like when to trigger liquidation. See the code.

Loan

The main module for giving out loans. Enables users to execute

adjustBalance, closeLoan 
transactions. Also notifies dapps about its state. See the code.

LiquidationObserver

Every

debtsPerCollateral 
module has this module observing price changes in order to trigger a liquidationOperation in case some loans get underwater. See the code.

A Sample User Scenario

A simple but powerful example of an interaction with our protocol can be the scenario where a user deposits money into a pool. Diagram below can help you understand what an end-to-end interaction would look like.

Deposit Sequence Diagram - Lending Protocol

Setup Your Environment

Prerequisites

You need to have the below dependencies in order to build and use the agoric-sdk.

  • Platform: Linux shell or equivalent

  • Node.js: An LTS version >= 14.x.x

  • yarn

  • git

Install agoric-sdk

We first need to clone the source code and build it in our local environment. A more detailed explanation about installation can be found in the docs, I'm just going over this briefly here.

Clone this repo any location you want in your machine

git clone https://github.com/Agoric/agoric-sdk.git

cd agoric-sdk

git checkout beta

git pull

Install dependencies

yarn install

Build the sdk

yarn build

Add agoric binary to the path

yarn link-cli 
~/bin/agoric
 

Check the version

agoric --version

Our protocol is built on the agoric-sdk beta branch so the version should be 0.15.0

Startup The Dapp

Get the code and checkout the blog/bytepitch branch.

git clone https://github.com/anilhelvaci/dapp-pool-lending-protocol.git

cd dapp-pool-lending-protocol

git checkout blog/bytepitch

git pull

Start a simulated chain

In Agoric there are two types of local test chains; a sim-chain and a local-chain. A sim-chain, simulated chain, is where we can test our dapps and contracts but there's no transaction cost. So it's simulated, not real. On the other hand there's a local-chain which is based on the cosmos-sdk, therefore it's based on GoLang. Starting a local-chain requires building some go packages. If you plan to test with multiple clients interacting with the same chain, local-chain is the way to go. Check this page for further information.

Go to dapp folder and start the sim-chain;

cd dapp-pool-lending-protocol 

agoric start --verbose --reset

For Agoric CLI reference see this page.

Leave that terminal running and open a new one;

cd dapp-pool-lending-protocol

agoric deploy contract/deploy/deploy.js api/deploy.js

A Word On Deployment

agoric deploy 
can
 
accept
 
multiple scripts as arguments and runs them in the order of passing. Here we pass two scripts;

  • contract/deploy/deploy.js: Sets up the required elements for the environment such as AMM, price authorities, faucets for the test tokens and then starts the actual LendingPool contract.

  • api/deploy.js: This scripts calls several other scripts in order to get tokens from faucets, create and add some liquidity to the pools. Basically we bootstrap the protocol with this script.

Once the deployment is done, start your wallet ui;

agoric open --repl

This command should open a browser automatically. Then open a new terminal and start the client ui;

cd dapp-pool-lending-protocol/ui

yarn start

Interact With The Dapp

To interact with the dapp, you mast approve it in your wallet. Go to your wallet and approve the dapp. Then go to localhost:3000, you should be able to see something like below;

open-protocol-markets

We have two main tabs in our app;

  • Markets: Displays general market data and enables you to Supply or Borrow money from a selected pool.

  • Activity: Shows the user's activity such as deposited assets and borrows. Also enables the user Redeem, Close or Adjust Loan.

Above screenshot belongs to the 'Markets' tab. Most of the data displayed there is self-explanatory here is some explanation for the ones that are not;

  • APY: Annual Percentage Yield is basically how much interest one is going to pay for a given debt and how much interest one is going to earn for their supplied assets. In compound these numbers are different from each other because of something called 'ReserveFactor'. ReserveFactor is subtracted from the Borrow APY to calculate the Supply APY. In our protocol we do not use a ReserveFactor so Supply and Borrow APYs are the same, that's why we have only one APY field on our dashboard.

  • MMR: Minimum Margin Requirement is the ratio between the value of collateral and the value of debt. This means that if you put $150 of collateral you can borrow $100 at most.

If you switch to the 'Activity' tab;

open-protocol-activity

Here we list the supplied assets and borrowed assets per pool.

As I mentioned in the section about deploy scripts, we bootstrap the protocol with some liquidity already pushed into it. That's why deposits side not empty.

I'll walk you through a full scenario where full functionality of the protocol where a user(you);

  • Deposit money to a pool

  • Borrow money from another pool using the protocol tokens you received when you deposit money to the first pool

  • Adjust your loan (pay some debt)

  • Close your loan (pay all your debt and get collateral in return)

  • Redeem your deposited money

Deposit Money

You might notice that the numbers you see in supply screenshots is inconsistent with rest of the screenshots, that's because I took them out of sync from the rest of the sequence.

Click on VAN market and below dialog should open

supply-dialog

Here, enter the amount you wish to supply and the protocol token you'll receive automatically be calculated, you can also specify slippage rate to protect your transaction from the sudden price changes of the market.

Then go to your wallet and approve the below offer;

wallet-supply-offer

Click 'Approve' then wait for the numbers in the purses change. Here we should care about VAN and AgVAN purses. Below is before transfer;

purses-before-supply

And this after the transaction;

purses-after-supply
Borrow Money

Let's borrow some VAN. Click on VAN market and switch to the 'Borrow' tab in the dialog. Then enter how much you want to borrow;

borrow-dialog

Go to your wallet and approve the transaction once you hit 'Borrow';

wallet-borrow

Purses will change from this;

purses-before-borrow

To this;

purses-after-borrow

You can see that 'TotalBorrow' for the VAN market is now increased, 'TotalSupply' is decreased and 'APY' is increased as there's less liquidity in the pool so the value of money is increased. Also you can see that 'TotalBorrow' for the user in profile is now $110.

markets-after-borrow

You can now view your loans in the 'Activity' tab;

activity-after-borrow

Notice that the exchange rate did not change because there's no interest accrued yet. So let's accrue some interest.

From the below screenshot you should notice that total borrows for both market and user profile is increased and also the exchange rate for VAN market is Increased also.

markets-after-interest

You can see that current debt for the loan is increased in 'Activity' tab also;

activity-after-interest
Adjust Loan

Let's pay some of our debt now. Go to 'Activity' tab and click on your loan. From the dialog opened, switch to 'Adjust' tab. From this dialog you can also request some of your collateral but here we'll just pay some of our debt.

adjust-dialog

Again, go to your wallet and approve the below transaction;

adjust-wallet

Purses before transaction passes;

purses-before-adjust

And after,

purses-after-adjust

In the 'Activity' tab you can see that the 'Borrow Balance' for your loan is decreased and '% Of Limit' is also updated;

activity-after-adjust
Close Loan

Now let's close our loan by paying all the remaining debt receiving the collateral we first put. Go to 'Close' tab in the loan dialog;

close-dialog

Go to your wallet approve the below transaction;

wallet-close-offer

Purses before close operation;

purses-before-close

And after;

purses-after-close

In the 'Activity' tab you can see that your loan is gone and your 'Total Borrow' is now $0;

activity-after-close
Redeem Your Money

Now click on your VAN deposit on the left side of 'Activity' dialog. Below dialog should pop;

redeem-dialog

Now go to your wallet and approve the transaction;

wallet-redeem-offer

Purses before redeem;

purses-before-redeem

And after;

purses-after-redeem

Conclusion

The following questions were answered in this article:

  • What Agoric is, how Agoric works, how Agoric development works

  • How to develop a smart contract with Agoric

  • How a pool based lending protocol works and it's most famous implementation (Compound Finance)

  • What our version of a pool based lending protocol looks like

  • An end-to-end user scenario

  • Real field implementations and practical examples of blockchain development, De-Fi development, DApp Development, Web3 development, Ethereum development, Smart Contract development, blockchain frameworks, blockchain protocols

I hope this article was helpful. Feel free to share your comments and questions in this issue. Thanks for reading. Until next time, take care!

« back to blog list