rDAI Basics: A Tutorial on Programming Interest with DeFi

Holders of DAI can permissionlessly earn interest on their stablecoin assets from multiple sources, including Maker’s Dai Savings Rate or through liquid lending pools like Compound. When using Compound, a user deposits DAI and receives cDAI (Compound’s token reflecting the current exchange rate for DAI) in exchange. When the user redeems from cDAI back to DAI, she will have more DAI than she started with, assuming at least one block (about 15 seconds) has elapsed, because Compound updates the exchange rate every block.

rDAI uses Compound to allow users to earn interest on DAI, but instead of redeeming the interest and principal back into the user’s wallet as one might do with a traditional bank savings account, it separates the principal from the interest. The principal is always under the original user’s control, but the interest is directed to flow wherever the rDAI instructions specify.

In this tutorial, we’ll first cover the main rDAI concepts that should help users and devs grasp how it works under the hood. Second, we’ll go through a couple of rDAI use cases to show you step-by-step how to program interest to flow wherever you like. Finally, we’ll link to a number of resources to help you build further on rDAI.

Q: What is the ratio of DAI to rDAI?

A: 1:1. One DAI = one rDAI.

rDAI uses a concept called a “hat” to contain the instructions for where the interest should flow. A hat is an object that contains two arrays:

  1. recipients, which lists the addresses (maximum 50 recipients per hat to prevent out of gas errors) that will receive the interest, and
  2. proportions, which specifies how much of the interest each address should receive.

Here’s an example:

New hats are created in rDAI through the createHat function. They are given sequential uint256 IDs and are immutable once created. Anyone can create a new rDAI hat as long as they pay the gas to do so. Creating a hat does not require holding DAI or minting rDAI yourself with the newly created hat — it just specifies a set of interest redirection instructions that other rDAI users can choose to follow by setting that hat.

An Ethereum address can only have one rDAI hat at a time.

This is illegal in rDAI. And dumb IRL.

An rDAI holder can call the changeHat function to swap to a different hat, but they cannot split the same address’ rDAI between two hats, nor can they modify an existing hat.

Minting rDAI requires a user to hold DAI. rDAI can be redeemed back to DAI at any time. You can transfer rDAI to to another address but for the purposes of this tutorial, we’ll just be looking at how a single user can mint rDAI from DAI and then redeem it back to DAI after some interest has accrued.

In order to mint rDAI from DAI, a user must first approve the DAI to be “spent” by the rDAI minting process. So the first step in minting rDAI is to tell the DAI contract that the DAI holder approves this usage of DAI. This is accomplished by the DAI contract’s ERC20 approve function. We’ll go over this step in detail below.

After the DAI approval step, there are three different functions that allow you to mint rDAI — mint, mintWithNewHat, and mintWithSelectedHat. They are easiest to explain in reverse order.

mintWithSelectedHat

Users that want to mint rDAI and redirect their interest to an existing set of instructions can do in one step using mintWithSelectedHat(mintAmount(uint256), hatID(uint256). This is a valuable use case for dapps that want to direct their users’ interest to the recipients the dapp has chosen.

For example the dapp rTrees, which allows users to plant real trees using rDAI interest, has its users call mintWithSelectedHat for hatID 11. That activates whatever DAI amount the user has specified and directs the interest to Trees for the Future, minus a small platform fee.

mintWithNewHat

Users that want to create a new custom hat and immediately start sending interest to it can use mintWithNewHat(mintAmount(uint256), recipients(address[]), proportions(uint32[])). This function essentially combines createHat and mintWithSelectedHat, pointing the newly minted rDAI to the newly created hat. Dapps may also wish to use this function to preserve pre-existing rDAI preferences. For instance, if a user was already sending interest on 50 rDAI to Charity X and wanted to now send interest on another 100 rDAI to Charity Y, the Charity Y dapp could create a new hat specifying proportions of 1/3rd to Charity X and 2/3rds to Charity Y and then mint 100 additional rDAI into this new hat. The 50 original rDAI that had been set to the earlier hat would be yanked into the new hat, and the user’s preference would be preserved through the creation of a new hat.

(NOTE: The plans for rDAI v2 include a strategy to make multiple rDAI allocations easier that what is described here).

mint

The mint(mintAmount(uint256)) function simply converts DAI to rDAI without further instruction. This leads to two different outcomes, depending on whether the user already has a hat set on their address.

If no hat has been set, this function will “create” a self-hat (one that is not reflected in the hatID array and so is not usable by other rDAI users) that redirects the interest to the user’s own account. It is functionally the same as using Compound to earn interest.

In the scenario where the user has already set a hat, mint will add the new rDAI to the same hat.

Redeeming

Redeeming is the process for converting rDAI back to DAI. There are two ways to redeem — redeemAll, which will convert all one’s rDAI to DAI (after claiming the accrued interest) and redeem(redeemTokens (uint256)), which allows a user to specify a particular amount of rDAI to redeem to DAI.

The rDAI contract also include redeemAndTransfer(redeemTo(address), redeemTokens(uint256)) as well as redeemAndTransferAll(redeemTo(address)), which allow a user with some amount of rDAI to swap it back to DAI and transfer the DAI to another address in a single transaction.

Accruing Interest and Token Balances

It’s worth taking a moment to explain where the interest is accruing, show you how to query the amount accrued, and to go over the steps needed to claim that interest and increment your rDAI token balance.

One misconception that some users and devs have regarding rDAI (and cDAI for that matter) is that the accruing interest automatically increases a user’s wallet token balance every block. This is not the case, because a transaction is always required to update token balances. Many front ends display incrementing balances based on the interest accrued to date, but this is a calculated representation of what one’s balance would be if a transaction were to claim the interest to date. The amount of accrued interest not yet reflected in your rDAI token balance can be read in the variable interestPayableOf(address) in the rDAI contract. To sweep that amount into your token balance, either payInterest or payInterestInternal must be called.

Let’s walk through the lifecycle of rDAI interest step by step to show what’s really going on when. For this example Alice will be redirecting 60% of her rDAI interest to Charity X, while keeping the remainder of the interest herself.

  1. Alice creates a custom hat with 60% of the interest going to Charity X and 40% going to her wallet address.
  2. Alice mints 100 rDAI from 100 DAI in her wallet and sets the hat to the newly created 60%/40% hat. As soon as the transaction is confirmed, Alice now has a balanceOf 100 rDAI in her wallet.
  3. Let’s imagine that enough time passes so that 10 rDAI in interest has accrued on the 100 rDAI. Yet at this time, Alice’s wallet still has a balanceOf 100 rDAI and Charity X’s wallet still has a balanceOf 0 rDAI.
  4. If we were to query interestPayableOf(Alice’s address), we would get 4 DAI in wei. If we were to query interestPayableOf(Charity X’s address), we would get 6 DAI in wei.
  5. To claim the amount of interestPayableOf, the function payInterest or payInterestInternal must be called. All rDAI actions call payInterestInternal before they occur, so that any amount of interestPayableOf is claimed before an action like redeem or transfer can occur.
  6. If Alice were to call payInterest(Alice’s address) and pay the gas for the transaction, she would have an rDAI balanceOf 104 after confirmation. Her interestPayableOf amount would reset to 0 but then begin ticking up again because interest is still accruing according to the hat instructions.
  7. Alice could be feeling doubly generous and also decide to call payInterest(Charity X’s address), thereby picking up the gas tab for Charity X claiming 6 rDAI. Anyone can call payInterest on any address — this simply sweeps the amount in interestPayableOf into rDAI tokens viewable in a user’s wallet. Again, this resets the interestPayableOf to 0 for Charity X, where it will begin ticking up.

TIP: This flow means that if you want to query the total amount of rDAI interest that an address has received, you need to track both interestPayableOf and balanceOf for an address.

ANOTHER TIP: The current values stored in interestPayableOf for all users are based on the current Compound exchange rate. This exchange rate is only updated with the Compound contract is “tickled” by someone performing a transaction on it. So in the event that no one tickles the contract for several blocks, the amount of interestPayableOf will not update during that time. Typically these delays don’t last more than a couple of blocks.

So now that we’ve covered the basic concepts and shared where to test them out for yourself, let’s walk through a couple use case examples to get some hands on experience. You’ll need MetaMask or another web3 wallet, some ETH and some DAI to follow along.

Use Case 1 — Send the Interest to Charity

First, we’ll need to set up the charity hat so that it can receive your rDAI interest.

In the picture at left I’m using the official rDai app to create a new hat (called “pool” on the site) for the Gitcoin Open Source Support Fund, which I’ve copied into the interface (it’s the address beginning “0x00De”). I’ve also opted to send 5% of the interest generated to support the rDAI dev DAO. This createHat transaction cost about 675,000 gas and created hatID 179.

To confirm that I created the hat correctly, I can query the newhatID on OneClickDapp by plugging “179” into getHatByID under the “Read” tab, which returns the following result:

You can see two addresses in the recipients array, and two very large proportions numbers. Because we can’t use decimals in Ethereum, the proportions are based on the maximum uint32 number, which is 4,294,967,295. The first number 214,748,364 is equivalent to ~5% of the maximum uint32 number. The second number 4,080,218,930 represents ~95% of that maximum.

OK so now we have created a specific hat to support a charity — let’s stream it some programmable interest! We’ll need a wallet with DAI in it and we’ll need to approve the rDAI contract to be able to “spend” our DAI by minting rDAI.

https://etherscan.io/token/0x6b175474e89094c44da98b954eedeac495271d0f#writeContract

Here I’m on the DAI token’s Etherscan interface. After connecting my wallet, I’ll need to call the approve function, providing the rDAI contract address (0x261b45D85cCFeAbb11F022eBa346ee8D1cd488c0) in the usr field and specifying approval to spend (the wad) up to 80 DAI in wei (meaning there are 19 zeros after the 8 — this wei converter is a useful tool if you use DAI in place of Ether).

We can verify that the allowance is approved by switching to the “Read Contract” tab and querying the allowance variable. You need to enter your wallet address in the first input field and the rDAI contract address in the second input field — here the Response at the bottom it shows an allowance of 80 DAI, just as we intended.

来源

What do you think?

发表评论

电子邮件地址不会被公开。 必填项已用*标注

Loading…

0

Comments

0 comments

tzBTC — Bitcoin on the Tezos blockchain

Komodo: AtomicDEX PRO Alpha, Micro Bounty Campaign, Ecosystem Updates