Build open financial tools using Compound and QuikNode

Open Finance is on the rise. Protocols are allowing people to lend and borrow tokens trustless via smart-contracts. In the last article, we talked about MakerDao and Dai JS (also fueling open and decentralized finance [#DeFi]). In this article, we will deep-dive into Compound Protocol and see how we can build Web3 applications on top of it.

What is Compound?

Compound Protocol enables trust-less borrowing and lending on the Ethereum Protocol.

“Compound is a money market protocol on the Ethereum blockchain — allowing individuals, institutions, and applications to frictionlessly earn interest on or borrow cryptographic assets without having to negotiate with a counterparty or peer”. [1]

How Compound Protocol Works?

The Compound Protocol (like any other protocol built on top of Ethereum) is a collection of Smart Contracts. Any individual can lock their Ether (also other assets) into Compound Protocol’s smart contract, this is what we call supply, and borrowers can borrow this supply at some interest rate. Let’s look at an example.

Let's say Ether (ETH) price is $200 and DAI is $1. Now you want to borrow 100 DAI, so you put $150 worth of ETH as collateral and receive 100 DAI. You need to pay an annual interest rate on the borrowed 100 DAI. When you pay back 100 DAI, you will get your collateral back.

Note- Compound team has launched V2 where this 150% collateral is now calculated on every asset (it means there will be different collateral for borrowing different assets).

Now if you don’t want to borrow and instead have some extra ETH (also other tokens supported by the protocol) lying around, you can earn interest by providing your asset as Supply to the Compound Protocol. You will earn an annual interest based on the supply you provide.

Where does the interest come from?

When one borrows from Compound, she needs to pay interest according to the interest rate (at the time of borrowing). Of this interest rate, Compound takes 5–10% (aka. sponsor equity) and the rest is spread out among suppliers.

If you have more questions about, quickly read this FAQs.

Now enough of economics, let's talk some code!

We will talk about Compound v2 which is still not on the main net, instead working on a testnet.

cTokens

Let’s first understand the cToken: these are simply ERC20 tokens for real assets on the Compound protocol. So if you want to use ZRX, Compound will wrap them into cToken and make it cZRX. There will be a separate contract for every asset. So to create borrowing and lending, we need these cTokens.

Now a deep-dive into the code: in this tutorial, we will borrow DAI and put ETH as collateral. Before that, a few things to note here:

  • Full code is here.
  • We are using Rinkeby testnet.
  • I added my private keys and address so it will be easy for you to run and test this. (DO NOT POST YOUR PRIVATE KEY PUBLICLY EVER).
  • You need a Web3 URL for accessing Rinkeby network (can spin up a QuikNode and get it here).
  • This Documentation, which we’ll reference often throughout the article.
const Web3 = require('web3')
const httpProvider = "YOUR_QUIKNODE_RINKEBY_URL"
var web3 = new Web3(new Web3.providers.HttpProvider(httpProvider));

//create account
// console.log(web3.eth.accounts.create(web3.utils.randomHex(32)));
const privateKey = "0x8679f89a15e31cbeb7256f37db1a6df215a103261e7c54dd90f8cba9eeba0c70";
const address = "0x3318B0C23621d70B7F22a694d7D7E78f37208AD2";

web3.eth.accounts.wallet.add({
    privateKey: '0x8679f89a15e31cbeb7256f37db1a6df215a103261e7c54dd90f8cba9eeba0c70',
    address: '0x3318B0C23621d70B7F22a694d7D7E78f37208AD2'
});


let cETH ="0xbed6d9490a7cd81ff0f06f29189160a9641a358f";

let CEther = new web3.eth.Contract(abi, cETH);
let cDAI = "0x2acc448d73e8d53076731fea2ef3fc38214d0a7d"
let cDaiInstance = new web3.eth.Contract(daiAbi, cDAI);
let comptroller = "0x8d2a2836d44d6735a2f783e6418caedb86da58d8";
const troll = new web3.eth.Contract(trollAbi, comptroller);


CEther.methods.supplyRatePerBlock().call().then((result) => {
	console.log(result /  1e18);

}).catch(error => console.log(error));

CEther.methods.mint().send({from: address, value: 2000000000000000000, gas : 2500000})
.on('transactionHash', (hash) => {
    console.log("hash", hash)
})
.on('confirmation', (confirmationNumber, receipt) => {
    console.log("confirmationNumber", confirmationNumber)
    console.log("receipt", receipt)

})
.on('receipt', (receipt) => {
    // receipt example
    console.log("receipt", receipt);
})
.on('error', console.error); 



troll.methods.enterMarkets([cETH, cDAI]).send({from: address  , gas : 2500000}).on('transactionHash', (hash) => {
    console.log("hash", hash)
})
.on('confirmation', (confirmationNumber, receipt) => {
    console.log("confirmationNumber", confirmationNumber)
    console.log("receipt", receipt)

})
.on('receipt', (receipt) => {
    // receipt example
    console.log("receipt", receipt);
})
.on('error', console.error); 




cDaiInstance.methods.borrow(5).send({from: address , gas : 2500000}).on('transactionHash', (hash) => {
    console.log("hash", hash)
})
.on('confirmation', (confirmationNumber, receipt) => {
    console.log("confirmationNumber", confirmationNumber)
    console.log("receipt", receipt)

})
.on('receipt', (receipt) => {
    // receipt example
    console.log("receipt", receipt);
})
.on('error', console.error); 


 cDaiInstance.methods.borrowBalanceCurrent(address).call().then(result => {
 	console.log(result.toNumber() / 1E18)
 })

Now let’s understand what we’re actually doing here. We need to have a cToken contract for ETH and DAI, which are cETH and cDAI. We will also need another contract called Comptroller, which manages the risk associated with the Compound Protocol v2. It is responsible for determining when accounts are underwater and can be liquidated. It determines how much collateral can be seized in exchange for liquidating an underwater account. It also provides a defense mechanism to protect the protocol against unforeseen attacks on the market.

let cETH ="0xbed6d9490a7cd81ff0f06f29189160a9641a358f";
let CEther = new web3.eth.Contract(abi, cETH);
let cDAI = "0x2acc448d73e8d53076731fea2ef3fc38214d0a7d"
let cDaiInstance = new web3.eth.Contract(daiAbi, cDAI);
let comptroller = "0x8d2a2836d44d6735a2f783e6418caedb86da58d8";
const troll = new web3.eth.Contract(trollAbi, comptroller);

We need to mint some cETH so we can use them borrow on Compound. The Compound Protocol only recognizes these minted tokens.

CEther.methods.mint().send({from: address, value: 2000000000000000000, gas : 2500000})
.on('transactionHash', (hash) => {
    console.log("hash", hash)
})
.on('confirmation', (confirmationNumber, receipt) => {
    console.log("confirmationNumber", confirmationNumber)
    console.log("receipt", receipt)
})
.on('receipt', (receipt) => {
    // receipt example
    console.log("receipt", receipt);
})
.on('error', console.error);

Here we are minting cETH for 2 Ether. The mint function transfers an asset into the money market, which begins accumulating interest based on the current Supply Rate for the asset. The number of tokens minted is the amount of underlying assets being provided divided by the current Exchange Rate.

Now we need to enable markets for both ETH and DAI tokens using the Comptroller Contract.

troll.methods.enterMarkets([cETH, cDAI]).send({from: address  , gas : 2500000}).on('transactionHash', (hash) => {
    console.log("hash", hash)
})
.on('confirmation', (confirmationNumber, receipt) => {
    console.log("confirmationNumber", confirmationNumber)
    console.log("receipt", receipt)
})
.on('receipt', (receipt) => {
    // receipt example
    console.log("receipt", receipt);
})
.on('error', console.error);

Now let’s borrow 5 DAI.

cDaiInstance.methods.borrow(5).send({from: address , gas : 2500000}).on('transactionHash', (hash) => {
    console.log("hash", hash)
})
.on('confirmation', (confirmationNumber, receipt) => {
    console.log("confirmationNumber", confirmationNumber)
    console.log("receipt", receipt)
})
.on('receipt', (receipt) => {
    // receipt example
    console.log("receipt", receipt);
})
.on('error', console.error);

That’s it, we borrowed 5 DAI! To see the balance:

cDaiInstance.methods.borrowBalanceCurrent(address).call().then(result => {
  console.log(result.toNumber() / 1E18)
 })

Your homework is to follow the Compound v2 Docs and repay my debt. =)

If you get stuck, start a discussion below — our community of peer Web3 devs is here to help!

About QuikNode

QuikNode is building infrastructure to support the future of Web3. Since 2017, we’ve worked with hundreds of developers & companies, helping scale dApps and providing high-performance Ethereum nodes. We’re working on something interesting from the past few months and will be launching soon, so subscribe our newsletter for more updates!! 😃