Skip to content

Instantly share code, notes, and snippets.

@samlaf
Created January 20, 2022 22:45
Show Gist options
  • Save samlaf/12150c9cf6f4c33b818e728359b7be0a to your computer and use it in GitHub Desktop.
Save samlaf/12150c9cf6f4c33b818e728359b7be0a to your computer and use it in GitHub Desktop.
toy implementation of compound and cEth (rebasing tokens)
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "hardhat/console.sol";
contract cEth is IERC20, Ownable {
uint256 public totalStaticSupply;
mapping (address => uint256) public staticSupply;
uint256 public supplyMultiplier = 1;
function totalSupply() public view returns (uint256) {
return totalStaticSupply * supplyMultiplier;
}
function balanceOf(address account) public view returns (uint256) {
return staticSupply[account] * supplyMultiplier;
}
function transfer(address recipient, uint256 amount) public returns (bool) {
require(balanceOf(msg.sender) >= amount, "Insufficient funds");
uint256 staticSupplyChange = amount / supplyMultiplier;
staticSupply[msg.sender] -= staticSupplyChange;
staticSupply[recipient] += staticSupplyChange;
return true;
}
// owner -> spender -> amount
mapping (address => mapping (address => uint256)) approvedAmounts; // not static!
function allowance(address owner, address spender) public view returns (uint256) {
return approvedAmounts[owner][spender];
}
function approve(address spender, uint256 amount) public returns (bool) {
require(amount <= balanceOf(msg.sender), "Insufficient balance");
approvedAmounts[msg.sender][spender] += amount;
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
require(amount <= approvedAmounts[sender][msg.sender], "Insufficient approved amount");
uint256 staticSupplyChange = amount / supplyMultiplier;
staticSupply[sender] -= staticSupplyChange;
staticSupply[recipient] += staticSupplyChange;
approvedAmounts[sender][msg.sender] -= amount;
return true;
}
function mint(address account, uint256 amount) public {
console.log(account, amount);
uint256 staticSupplyChange = amount / supplyMultiplier;
staticSupply[account] += staticSupplyChange;
totalStaticSupply += staticSupplyChange;
}
function adjustSupplyMultiplier(uint256 x) public onlyOwner {
supplyMultiplier *= x;
}
}
contract compound is Ownable {
cEth public _ceth;
uint256 totalEthReserves; // includes borrowed amounts
mapping (address => uint256) public borrowedAmount;
uint256 interest_rate = 2.0; // fixed in time for now
constructor() {
_ceth = new cEth();
}
function deposit() public payable {
require(msg.value > 0, "Must deposit a positive amount");
_ceth.mint(msg.sender, msg.value);
totalEthReserves += msg.value;
}
// We only allow a single borrow per person.
// So if you need to borrow more, you need to first repay your original loan.
function borrow(uint256 amount) public {
require(amount < address(this).balance, "Insufficient funds in the pool");
borrowedAmount[msg.sender] += amount;
(bool sent, ) = msg.sender.call{value: amount}("");
require(sent, "Eth transfer failed");
}
// right now we only allow repaying the entire borrowed amount
function repayAll() public payable {
console.log(msg.value, borrowedAmount[msg.sender] * interest_rate, interest_rate);
require(msg.value == borrowedAmount[msg.sender] * interest_rate);
uint256 newAmountOfEth = msg.value - borrowedAmount[msg.sender];
uint256 newTotalEthReserves = totalEthReserves + newAmountOfEth;
// TODO: this doesn't work... no fractions in Solidity!
// have to find another way to do this..
uint256 multiplier = newTotalEthReserves / totalEthReserves;
_ceth.adjustSupplyMultiplier(multiplier);
totalEthReserves = newTotalEthReserves;
borrowedAmount[msg.sender] = 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment