Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions contracts/interfaces/IChai.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
pragma solidity 0.4.24;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "../interfaces/IPot.sol";

interface IChai {
function pot() external view returns (IPot);
function daiToken() external view returns (ERC20);
function balanceOf(address) external view returns (uint256);
function dai(address) external view returns (uint256);
function join(address, uint256) external;
function draw(address, uint256) external;
function exit(address, uint256) external;
function transfer(address, uint256) external;
}
7 changes: 7 additions & 0 deletions contracts/interfaces/IPot.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pragma solidity 0.4.24;

interface IPot {
function chi() external view returns (uint256);
function rho() external view returns (uint256);
function drip() external returns (uint256);
}
13 changes: 13 additions & 0 deletions contracts/mocks/BridgeValidatorsDeterministic.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pragma solidity 0.4.24;

import "../upgradeable_contracts/BridgeValidators.sol";

contract BridgeValidatorsDeterministic is BridgeValidators {
function isValidatorDuty(address _validator) external view returns (bool) {
address next = getNextValidator(F_ADDR);
require(next != address(0));

// first validator is always on duty, others are always not
return _validator == next;
}
}
198 changes: 198 additions & 0 deletions contracts/mocks/ChaiMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// chai.sol -- a dai savings token
// Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico, lucasvo, livnev

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

/* solhint-disable */
pragma solidity 0.4.24;

contract VatLike {
function hope(address) external;
}

contract PotLike {
function chi() external returns (uint256);
function rho() external returns (uint256);
function drip() external returns (uint256);
function join(uint256) external;
function exit(uint256) external;
}

contract JoinLike {
function join(address, uint256) external;
function exit(address, uint256) external;
}

contract GemLike {
function transferFrom(address, address, uint256) external returns (bool);
function approve(address, uint256) external returns (bool);
}

contract ChaiMock {
// --- Data ---
VatLike public vat = VatLike(0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B);
PotLike public pot = PotLike(0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7);
JoinLike public daiJoin = JoinLike(0x9759A6Ac90977b93B58547b4A71c78317f391A28);
GemLike public daiToken = GemLike(0x6B175474E89094C44Da98b954EedeAC495271d0F);

// --- ERC20 Data ---
string public constant name = "Chai";
string public constant symbol = "CHAI";
string public constant version = "1";
uint8 public constant decimals = 18;
uint256 public totalSupply;

mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
mapping(address => uint256) public nonces;

event Approval(address indexed src, address indexed guy, uint256 wad);
event Transfer(address indexed src, address indexed dst, uint256 wad);

// --- Math ---
uint256 constant RAY = 10**27;
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x + y) >= x);
}
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x - y) <= x);
}
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x);
}
function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
// always rounds down
z = mul(x, y) / RAY;
}
function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
// always rounds down
z = mul(x, RAY) / y;
}
function rdivup(uint256 x, uint256 y) internal pure returns (uint256 z) {
// always rounds up
z = add(mul(x, RAY), sub(y, 1)) / y;
}

// --- EIP712 niceties ---
bytes32 public constant DOMAIN_SEPARATOR = 0x0b50407de9fa158c2cba01a99633329490dfd22989a150c20e8c7b4c1fb0fcc3;
// keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)"));
bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb;

constructor(address _vat, address _pot, address _daiJoin, address _dai) public {
vat = VatLike(_vat);
pot = PotLike(_pot);
daiJoin = JoinLike(_daiJoin);
daiToken = GemLike(_dai);

vat.hope(address(daiJoin));
vat.hope(address(pot));

daiToken.approve(address(daiJoin), uint256(-1));
}

// --- Token ---
function transfer(address dst, uint256 wad) external returns (bool) {
return transferFrom(msg.sender, dst, wad);
}
// like transferFrom but dai-denominated
function move(address src, address dst, uint256 wad) external returns (bool) {
uint256 chi = (now > pot.rho()) ? pot.drip() : pot.chi();
// rounding up ensures dst gets at least wad dai
return transferFrom(src, dst, rdivup(wad, chi));
}
function transferFrom(address src, address dst, uint256 wad) public returns (bool) {
require(balanceOf[src] >= wad, "chai/insufficient-balance");
if (src != msg.sender && allowance[src][msg.sender] != uint256(-1)) {
require(allowance[src][msg.sender] >= wad, "chai/insufficient-allowance");
allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad);
}
balanceOf[src] = sub(balanceOf[src], wad);
balanceOf[dst] = add(balanceOf[dst], wad);
emit Transfer(src, dst, wad);
return true;
}
function approve(address usr, uint256 wad) external returns (bool) {
allowance[msg.sender][usr] = wad;
emit Approval(msg.sender, usr, wad);
return true;
}

// --- Approve by signature ---
function permit(
address holder,
address spender,
uint256 nonce,
uint256 expiry,
bool allowed,
uint8 v,
bytes32 r,
bytes32 s
) external {
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, holder, spender, nonce, expiry, allowed))
)
);
require(holder != address(0), "chai/invalid holder");
require(holder == ecrecover(digest, v, r, s), "chai/invalid-permit");
require(expiry == 0 || now <= expiry, "chai/permit-expired");
require(nonce == nonces[holder]++, "chai/invalid-nonce");

uint256 can = allowed ? uint256(-1) : 0;
allowance[holder][spender] = can;
emit Approval(holder, spender, can);
}

function dai(address usr) external returns (uint256 wad) {
uint256 chi = (now > pot.rho()) ? pot.drip() : pot.chi();
wad = rmul(chi, balanceOf[usr]);
}
// wad is denominated in dai
function join(address dst, uint256 wad) external {
uint256 chi = (now > pot.rho()) ? pot.drip() : pot.chi();
uint256 pie = rdiv(wad, chi);
balanceOf[dst] = add(balanceOf[dst], pie);
totalSupply = add(totalSupply, pie);

daiToken.transferFrom(msg.sender, address(this), wad);
daiJoin.join(address(this), wad);
pot.join(pie);
emit Transfer(address(0), dst, pie);
}

// wad is denominated in (1/chi) * dai
function exit(address src, uint256 wad) public {
require(balanceOf[src] >= wad, "chai/insufficient-balance");
if (src != msg.sender && allowance[src][msg.sender] != uint256(-1)) {
require(allowance[src][msg.sender] >= wad, "chai/insufficient-allowance");
allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad);
}
balanceOf[src] = sub(balanceOf[src], wad);
totalSupply = sub(totalSupply, wad);

uint256 chi = (now > pot.rho()) ? pot.drip() : pot.chi();
pot.exit(wad);
daiJoin.exit(msg.sender, rmul(chi, wad));
emit Transfer(src, address(0), wad);
}

// wad is denominated in dai
function draw(address src, uint256 wad) external {
uint256 chi = (now > pot.rho()) ? pot.drip() : pot.chi();
// rounding up ensures usr gets at least wad dai
exit(src, rdivup(wad, chi));
}
}
25 changes: 25 additions & 0 deletions contracts/mocks/ChaiMock2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
pragma solidity 0.4.24;

contract GemLike {
function transferFrom(address, address, uint256) external returns (bool);
}

/**
* @title ChaiMock2
* @dev This contract is used for e2e tests only,
* bridge contract requires non-empty chai stub with correct daiToken value and possibility to call join
*/
contract ChaiMock2 {
GemLike public daiToken;
uint256 internal daiBalance;

// wad is denominated in dai
function join(address, uint256 wad) external {
daiToken.transferFrom(msg.sender, address(this), wad);
daiBalance += wad;
}

function dai(address) external view returns (uint256) {
return daiBalance;
}
}
74 changes: 74 additions & 0 deletions contracts/mocks/DaiJoinMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/// join.sol -- Basic token adapters

// Copyright (C) 2018 Rain <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

/* solhint-disable */
pragma solidity 0.4.24;

contract DSTokenLike {
function mint(address, uint256) external;
function burn(address, uint256) external;
function allowance(address, address) external returns (uint256);
}

contract VatLike {
function slip(bytes32, address, int256) external;
function move(address, address, uint256) external;
function setDai(address, uint256) external;
}

contract DaiJoinMock {
// --- Auth ---
mapping(address => uint256) public wards;
function rely(address usr) external auth {
wards[usr] = 1;
}
function deny(address usr) external auth {
wards[usr] = 0;
}
modifier auth {
require(wards[msg.sender] == 1, "DaiJoin/not-authorized");
_;
}

VatLike public vat;
DSTokenLike public dai;
uint256 public live; // Access Flag

constructor(address vat_, address dai_) public {
wards[msg.sender] = 1;
live = 1;
vat = VatLike(vat_);
dai = DSTokenLike(dai_);
vat.setDai(address(this), mul(ONE, ONE));
}
function cage() external auth {
live = 0;
}
uint256 constant ONE = 10**27;
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x);
}
function join(address usr, uint256 wad) external {
vat.move(address(this), usr, mul(ONE, wad));
dai.burn(msg.sender, wad);
}
function exit(address usr, uint256 wad) external {
require(live == 1, "DaiJoin/not-live");
vat.move(msg.sender, address(this), mul(ONE, wad));
dai.mint(usr, wad);
}
}
Loading