Skip to content
This repository has been archived by the owner on Sep 5, 2021. It is now read-only.

Commit

Permalink
Integration of Uniswap #1
Browse files Browse the repository at this point in the history
  • Loading branch information
burningtree committed Feb 18, 2020
1 parent 10e3759 commit 3c6e0b9
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 73 deletions.
151 changes: 92 additions & 59 deletions contracts/DCZK.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pragma solidity ^0.5.16;

interface IERC20 {
contract IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
Expand All @@ -13,16 +13,16 @@ interface IERC20 {
event Approval(address indexed owner, address indexed spender, uint256 value);
}

interface IVat {
contract Vat {
function hope(address) external;
}

interface IDaiJoin {
contract DaiJoin {
function join(address, uint) external;
function exit(address, uint) external;
}

interface IPot {
contract Pot {
function chi() external view returns (uint256);
function rho() external view returns (uint256);
function dsr() external view returns (uint256);
Expand All @@ -32,6 +32,16 @@ interface IPot {
function exit(uint256) external;
}

contract UniswapFactoryInterface {
function getExchange(address token) external view returns (address exchange);
}

contract UniswapExchangeInterface {
function getEthToTokenInputPrice(uint256 eth_sold) external view returns (uint256 tokens_bought);
function ethToTokenSwapInput(uint256 min_tokens, uint256 deadline) external payable returns (uint256 tokens_bought);
function tokenToEthTransferInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline, address recipient) external returns (uint256 eth_bought);
}

contract DCZK is IERC20 {

// --- ERC20 Events ---
Expand All @@ -46,32 +56,38 @@ contract DCZK is IERC20 {
event Sell(address indexed seller, uint256 dczk, uint256 dai);
event AddLiquidity(uint256 rate, uint256 amount);
event RateUpdate(uint256 rate, address caller);
event BuyWithEther(address indexed buyer, uint256 dczk, uint256 dai, uint256 eth);
event SellForEther(address indexed seller, uint256 dczk, uint256 dai, uint256 eth);
event Debug(uint256 value);

// --- ERC20 basic vars ---
string private _name = "dCZK Test v0.2";
string private _symbol = "dCZK02";
uint8 private _decimals = 18;
string public constant name = "dCZK Test v0.2.1";
string public constant symbol = "dCZK021";
uint8 public constant decimals = 18;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;

// --- Data ---
IERC20 public depositToken;
IVat public vat;
IDaiJoin public daiJoin;
IPot public pot;
IERC20 public depositToken;
Vat public vat;
DaiJoin public daiJoin;
Pot public pot;
UniswapFactoryInterface public uniswapFactory;
UniswapExchangeInterface public depositTokenExchange;

uint256 public lrho;
uint256 public lchi;
uint256 public rate = 22000000000000000000; // basic CZKDAI rate
uint256 public maxRate;
uint256 public totalVolume;
uint public lastUpdate;
uint256 public rate = 22000000000000000000;

// fixed oracleAdress - will be not included in mainnet release
address public oracleAddress = 0x89188bE35B16AF852dC0A4a9e47e0cA871fadf9a;

uint16 constant fee = 400; // 0.25%
address public constant oracleAddress = 0x89188bE35B16AF852dC0A4a9e47e0cA871fadf9a;
uint256 public constant fee = 400; // 0.25%
uint256 constant uniswapDeadline = 900 * 60; // 15 minutes

uint256 public maxRate;
uint256 public totalVolume;
uint256 public lastUpdate;
struct Thread {
uint next;
uint amount;
Expand All @@ -80,26 +96,30 @@ contract DCZK is IERC20 {


// --- Init ---
constructor (address _dai, address _vat, address _daiJoin, address _pot) public {
constructor (address _dai, address _vat, address _daiJoin, address _pot, address _uniswapFactory) public {
// set DAI address
depositToken = IERC20(_dai);

// DSR - DAI Savings Rate
daiJoin = IDaiJoin(_daiJoin);
vat = IVat(_vat);
pot = IPot(_pot);
daiJoin = DaiJoin(_daiJoin);
vat = Vat(_vat);
pot = Pot(_pot);
// pot = new Pot(address(this)); // MakerDAO DSR `pot` (for testing purposes)
vat.hope(address(daiJoin));
vat.hope(address(pot));

// Uniswap
uniswapFactory = UniswapFactoryInterface(_uniswapFactory);
depositTokenExchange = UniswapExchangeInterface(uniswapFactory.getExchange(address(depositToken)));

depositToken.approve(address(daiJoin), uint(-1));
}

// --- Math ---
// Taken from official DSR contract:
// https://github.com/makerdao/dss/blob/master/src/pot.sol

uint constant RAY = 10 ** 27;
/*uint constant RAY = 10 ** 27;
function rpow(uint x, uint n, uint base) internal pure returns (uint z) {
assembly {
switch x case 0 {switch n case 0 {z := base} default {z := 0}}
Expand All @@ -122,7 +142,7 @@ contract DCZK is IERC20 {
}
}
}
}
}*/

function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x);
Expand Down Expand Up @@ -157,18 +177,6 @@ contract DCZK is IERC20 {

// --- ERC20 Token ---

function name() public view returns (string memory) {
return _name;
}

function symbol() public view returns (string memory) {
return _symbol;
}

function decimals() public view returns (uint8) {
return _decimals;
}

function totalSupply() public view returns (uint256) {
return rmul(_chi(), _totalSupply);
}
Expand Down Expand Up @@ -268,7 +276,7 @@ contract DCZK is IERC20 {
return pot.pie(address(this));
}

// --- Minting (internal) ---
// --- Minting and burning (internal) ---

function _mint(address dst, uint256 czk, uint256 dai) private {
require(dst != address(0), "ERC20: mint to the zero address");
Expand All @@ -287,9 +295,7 @@ contract DCZK is IERC20 {
emit Mint(dst, czk, spie);
}

// --- Burning (internal) ---

function _burn(address src, uint256 czk, uint256 dai) private {
function _burn(address src, uint256 czk, uint256 dai, address dst) private {
require(src != address(0), "ERC20: burn from the zero address");
require(balanceOf(src) >= czk, "dczk/insufficient-balance");

Expand All @@ -298,17 +304,18 @@ contract DCZK is IERC20 {

_balances[src] = sub(_balances[src], spie, "ERC20: burn amount exceeds balance");
_totalSupply = sub(_totalSupply, spie);
emit Transfer(src, address(0), czk);
emit Burn(src, czk, spie);

uint pie = rdivup(dai, chi);
if (pie != 0) {
pot.exit(pie);
daiJoin.exit(msg.sender, rmul(chi, pie));
daiJoin.exit(dst, rmul(chi, pie));
}
if (dst != address(this)) {
_approve(src, dst, sub(_allowances[src][address(this)], czk, "ERC20: burn amount exceeds allowance"));
}

_approve(src, msg.sender, sub(_allowances[src][address(this)], czk, "ERC20: burn amount exceeds allowance"));
emit Transfer(src, address(0), czk);
emit TransferPrincipal(src, address(0), spie, czk);
emit Burn(src, czk, spie);
}

// --- DEX Decentralized exchange ---
Expand Down Expand Up @@ -341,14 +348,10 @@ contract DCZK is IERC20 {
txs[rate].amount += amount;
}

function buy(uint256 amount) public {
function _buyAndMint(uint256 amount) private returns(uint256 converted) {
require(rate != 0, "rate cannot be 0");
require(depositToken.allowance(msg.sender, address(this)) >= amount, "dczk/insufficient-allowance");
_drip();

// transfer DAI to this contract
depositToken.transferFrom(msg.sender, address(this), amount);

// calculate fee - 0.25%
uint _fee = amount / fee;
uint rest = amount - _fee;
Expand All @@ -358,18 +361,18 @@ contract DCZK is IERC20 {
_addLiquidity(rest);

// convert to stablecoin amount
uint _converted = (rest * rate) / 10 ** 18;
converted = (rest * rate) / 10 ** 18;

// save amount to total volume
totalVolume += _converted;
totalVolume += converted;

// mint tokens
_mint(address(msg.sender), _converted, rest);
_mint(address(msg.sender), converted, rest);

emit Buy(msg.sender, _converted, rest);
emit Buy(msg.sender, converted, rest);
}

function sell(uint256 amount) public {
function _sell(uint256 amount) private returns(uint256 deposit) {
require(maxRate != 0, "max_rate cannot be 0");
require(allowance(msg.sender, address(this)) >= amount, "czk/insufficient-allowance");
_drip();
Expand All @@ -379,7 +382,7 @@ contract DCZK is IERC20 {

// calculate rate & deposit
uint _amount = amount;
uint deposit = 0;
deposit = 0;
uint currentRate = maxRate;
while (_amount > 0) {
uint full = (txs[currentRate].amount * currentRate) / 10 ** 18;
Expand All @@ -398,9 +401,6 @@ contract DCZK is IERC20 {
currentRate = txs[currentRate].next;
}
}
// burn coins
_burn(msg.sender, amount, deposit);

emit Sell(msg.sender, amount, deposit);
}

Expand Down Expand Up @@ -428,6 +428,39 @@ contract DCZK is IERC20 {
}
}

function buy(uint256 amount) public {
require(depositToken.allowance(msg.sender, address(this)) >= amount, "dczk/insufficient-allowance");
depositToken.transferFrom(msg.sender, address(this), amount);
_buyAndMint(amount);
}

function sell(uint256 amount) public {
uint256 deposit = _sell(amount);
_burn(msg.sender, amount, deposit, msg.sender);
}

// --- Uniswap Integration ---

function buyWithEther(uint256 minTokens) public payable returns(uint256 converted) {
uint256 deposit = depositTokenExchange.ethToTokenSwapInput.value(msg.value)(minTokens, now + uniswapDeadline);
converted = _buyAndMint(deposit);
emit BuyWithEther(msg.sender, converted, deposit, uint256(msg.value));
}

function sellForEther(uint256 amount, uint256 minEth) public returns(uint256 eth) {
uint256 deposit = _sell(amount);
_burn(msg.sender, amount, deposit, address(this));
depositToken.approve(address(depositTokenExchange), deposit);
eth = depositTokenExchange.tokenToEthTransferInput(deposit, minEth, now + uniswapDeadline, msg.sender);
emit SellForEther(msg.sender, amount, deposit, eth);
}

function () external payable {
require(msg.data.length == 0);
uint256 price = depositTokenExchange.getEthToTokenInputPrice(msg.value);
buyWithEther(sub(price, price / 40));
}

// --- Oracle ---

function updateRate(uint _rate) public {
Expand Down
5 changes: 3 additions & 2 deletions migrations/2_deploy.js → migrations/1_deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ const DCZK = artifacts.require('DCZK')
module.exports = async function (deployer) {
await deployer.deploy(
DCZK,
'0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa', // DAI
'0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa', // DAI token
'0xbA987bDB501d131f766fEe8180Da5d81b34b69d9', // DAI/vat
'0x5AA71a3ae1C0bd6ac27A1f28e1415fFFB6F15B8c', // DAI/daiJoin
'0xEA190DBDC7adF265260ec4dA6e9675Fd4f5A78bb' // DAi/pot
'0xEA190DBDC7adF265260ec4dA6e9675Fd4f5A78bb', // DAi/pot
'0xD3E51Ef092B2845f10401a0159B2B96e8B6c3D30' // Uniswap Factory
)
}
6 changes: 0 additions & 6 deletions migrations/1_initial_migration.js

This file was deleted.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"description": "",
"main": "truffle-config.js",
"scripts": {
"deploy": "truffle migrate --network kovan",
"verify": "truffle run verify DCZK --network kovan",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
Expand Down
12 changes: 6 additions & 6 deletions truffle-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ module.exports = {
solc: {
// version: "0.5.8", // Fetch exact version from solc-bin (default: truffle's version)
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
// settings: { // See the solidity docs for advice about optimization and evmVersion
// optimizer: {
// enabled: false,
// runs: 200
// },
settings: { // See the solidity docs for advice about optimization and evmVersion
optimizer: {
enabled: true,
runs: 100000
}
// evmVersion: "byzantium"
// }
}
}
},
plugins: [
Expand Down

0 comments on commit 3c6e0b9

Please sign in to comment.