Skip to content
This repository has been archived by the owner on Mar 1, 2024. It is now read-only.

Commit

Permalink
trustless bridge
Browse files Browse the repository at this point in the history
  • Loading branch information
jdkanani committed Feb 12, 2018
1 parent 92b8ce2 commit 87243db
Show file tree
Hide file tree
Showing 27 changed files with 2,708 additions and 120 deletions.
2 changes: 1 addition & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"presets": ["es2015", "stage-2", "stage-3"]
"presets": ["env"]
}
7 changes: 7 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
parser: 'babel-eslint',
extends: 'standard',
rules: {
'space-before-function-paren': ['error', 'never']
}
}
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sol linguist-language=Solidity
9 changes: 9 additions & 0 deletions .solhint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "default",
"rules": {
"avoid-throw": false,
"avoid-suicide": "error",
"avoid-sha3": "warn",
"indent": ["warn", 2]
}
}
12 changes: 6 additions & 6 deletions contracts/MaticChannel.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.4.17;
pragma solidity 0.4.18;

import './token/StandardToken.sol';
import "./lib/ECVerify.sol";
Expand Down Expand Up @@ -167,19 +167,19 @@ contract MaticChannel {
/// @param token The token address for withdraw
/// @param balance The total token amount for withdraw
/// @param sig The signature which receiver receives from owner as part of payment
/// @param maticSig The signature which receiver receives from matic network as part of payment validation
function withdraw(address receiver, address token, uint256 balance, bytes sig, bytes maticSig) public {
/// @param proof Withdraw proof from plasma chain
function withdraw(address receiver, address token, uint256 balance, bytes sig, bytes proof) public {
// check for receiver and token
require(receiver != 0x0 && token != 0x0);

bytes32 orderId = generateOrderId(receiver);
bytes32 messageHash = getBalanceMessage(receiver, token, orderId, balance);
address signer = ECVerify.ecrecovery(messageHash, sig);
address maticSigner = ECVerify.ecrecovery(messageHash, maticSig);
// address maticSigner = ECVerify.ecrecovery(messageHash, maticSig);

require(signer == owner);
require(maticSigner == matic);
require(signer != maticSigner); // matic address shouldn't be same as signer
// require(maticSigner == matic);
// require(signer != maticSigner); // matic address shouldn't be same as signer
require(tokenManagers[token].deposit >= balance);

// change order index for receiver
Expand Down
4 changes: 2 additions & 2 deletions contracts/MaticProtocol.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.4.18;
pragma solidity 0.4.18;

import "./lib/ECVerify.sol";
import "./mixin/Ownable.sol";
Expand Down Expand Up @@ -67,7 +67,7 @@ contract MaticProtocol is Ownable {
/// @param _challengePeriod Challege period for settlement.
/// @return Returns address of created contract.
function createMaticChannel(address _creator, uint8 _challengePeriod) public payable enoughPaid returns (address) {
MaticChannel channel = new MaticChannel(_creator, owner, _challengePeriod);
MaticChannel channel = new MaticChannel(_creator, address(this), _challengePeriod);

// register created channel
contractMap[channel] = true;
Expand Down
2 changes: 1 addition & 1 deletion contracts/Migrations.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.4.17;
pragma solidity 0.4.18;

contract Migrations {
address public owner;
Expand Down
253 changes: 253 additions & 0 deletions contracts/RootChain.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
pragma solidity 0.4.18;

import './lib/SafeMath.sol';
import "./lib/ECVerify.sol";
import './lib/RLP.sol';
import "./mixin/Ownable.sol";

import "./token/ERC20.sol";

contract RootChain is Ownable {
using SafeMath for uint256;
using RLP for bytes;
using RLP for RLP.RLPItem;
using RLP for RLP.Iterator;

// chain identifier (protection against replay attacks)
bytes32 public chain = keccak256('Matic Network v0.0.1-beta.1');

// stake token address
address public stakeToken;

// The randomness seed of the epoch.
// This is used to determine the proposer and the validator pool
bytes32 public epochSeed = keccak256(block.difficulty + block.number + now);

// header block
struct HeaderBlock {
bytes32 root;
uint256 start;
uint256 end;
uint256 createdAt;
}

mapping(uint256 => HeaderBlock) public headerBlocks;
uint256 public currentHeaderBlock;

// validator threshold
uint256 public validatorThreshold = 0;

// Pool of stakers and validators
struct Stake {
uint256 amount;
address staker;
}

mapping(address => uint256) public stakers;
Stake[] public stakeList;
uint256 public totalStake;

// Constructor
function RootChain(address token) public {
stakeToken = token;
}

//
// Events
//
event Deposit(address indexed user, address indexed token, uint256 amount);
event NewHeaderBlock(
address indexed proposer,
uint256 indexed start,
uint256 indexed end,
bytes32 root
);

//
// Modifier
//

// only staker
modifier onlyStaker() {
require(isStaker(msg.sender));
_;
}

// Change the number of validators required to allow a passed header root
function updateValidatorThreshold(uint256 newThreshold) public onlyOwner {
validatorThreshold = newThreshold;
}

//
// Staker functions
//
function stake(uint256 amount) public {
require(amount > 0);

ERC20 t = ERC20(stakeToken);
require(t.transferFrom(msg.sender, address(this), amount));

// check staker is present or not
if (stakers[msg.sender] == 0) {
// actual staker cannot be on index 0
if (stakeList.length == 0) {
stakeList.push(Stake({
amount: 0,
staker: address(0x0)
}));
}

// add new stake
stakeList.push(Stake({
amount: 0,
staker: msg.sender
}));
stakers[msg.sender] = stakeList.length - 1;
}

// add amount
stakeList[stakers[msg.sender]].amount = getStake(msg.sender).add(amount);

// update total stake
totalStake = totalStake.add(amount);
}

// Remove stake
function destake(uint256 amount) public onlyStaker {
uint256 currentStake = getStake(msg.sender);
require(amount <= currentStake);
stakeList[stakers[msg.sender]].amount = currentStake.sub(amount);

// reduce total stake
totalStake = totalStake.sub(amount);

// transfer stake amount
ERC20 t = ERC20(stakeToken);
t.transfer(msg.sender, amount);
}

//
// User functions
//

// Any user can deposit
function deposit(address token, uint256 amount) public {
// transfer tokens to current contract
ERC20 t = ERC20(token);
require(t.transferFrom(msg.sender, address(this), amount));

// broadcast deposit events
Deposit(msg.sender, token, amount);
}

function submitHeaderBlock(bytes32 root, uint256 end, bytes sigs) public {
uint256 lastBlock = currentChildBlock();

// Make sure we are adding blocks
require(end > lastBlock.add(1));

// Make sure enough validators sign off on the proposed header root
require(
checkSignatures(root, lastBlock.add(1), end, sigs) >= validatorThreshold
);

// Add the header root
HeaderBlock memory headerBlock = HeaderBlock({
root: root,
start: lastBlock.add(1),
end: end,
createdAt: block.timestamp
});
headerBlocks[currentHeaderBlock] = headerBlock;
currentHeaderBlock = currentHeaderBlock.add(1);

// Calculate the reward and issue it
// uint256 r = reward.base + reward.a * (end - lastBlock[chainId]);
// If we exceed the max reward, anyone can propose the header root
// if (r > maxReward) {
// r = maxReward;
// } else {
// require(msg.sender == getProposer());
// }
// msg.sender.transfer(r);

NewHeaderBlock(
msg.sender,
headerBlock.start,
headerBlock.end,
root
);

// set epoch seed
epochSeed = keccak256(block.difficulty + block.number + now);
}

function currentChildBlock() public view returns(uint256) {
return headerBlocks[currentHeaderBlock].end;
}

// Sample a proposer. Likelihood of being chosen is proportional to stake size.
function getProposer() public constant returns (address) {
// Convert the seed to an index
uint256 target = uint256(epochSeed) % totalStake;
// Index of stake list
uint64 i = 1;
// Total stake
uint256 sum = 0;
while (sum < target) {
sum += stakeList[i].amount;
i += 1;
}

return stakeList[i - 1].staker;
}

function getStake(address a) public view returns (uint256) {
return stakeList[stakers[a]].amount;
}

function getStakeIndex(address a) public view returns (uint256) {
return stakers[a];
}

function isStaker(address a) public view returns (bool) {
return stakeList[stakers[a]].amount > 0;
}

function checkSignatures(
bytes32 root,
uint256 start,
uint256 end,
bytes sigs
) public view returns (uint256) {
// create hash
bytes32 h = keccak256(chain, root, start, end);

// total signers
uint256 totalSigners = 0;

// get sig list
var sigList = sigs.toRLPItem().toList();
address[] memory uniqueStakers = new address[](sigList.length);
for (uint64 i = 0; i < sigList.length; i += 1) {
address signer = ECVerify.ecrecovery(h, sigList[i].toData());
bool duplicate = false;

if (isStaker(signer)) { // check if signer is stacker
for (uint64 j = 0; j < i; j += 1) {
if (uniqueStakers[j] == signer) {
duplicate = true;
break;
}
}
}

if (duplicate == false) {
uniqueStakers[i] = signer;
totalSigners++;
}
}

return totalSigners;
}
}
3 changes: 2 additions & 1 deletion contracts/SafeMath.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pragma solidity ^0.4.17;
pragma solidity 0.4.18;


/**
* @title SafeMath
Expand Down
2 changes: 1 addition & 1 deletion contracts/TestToken.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.4.17;
pragma solidity 0.4.18;

import "./token/StandardToken.sol";

Expand Down
8 changes: 4 additions & 4 deletions contracts/lib/ECVerify.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pragma solidity ^0.4.17;
pragma solidity 0.4.18;

library ECVerify {
function ecrecovery(bytes32 hash, bytes sig) internal pure returns (address) {
function ecrecovery(bytes32 hash, bytes sig) public pure returns (address) {
bytes32 r;
bytes32 s;
uint8 v;
Expand Down Expand Up @@ -34,7 +34,7 @@ library ECVerify {
return result;
}

function ecrecovery(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
function ecrecovery(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public pure returns (address) {
// get address out of hash and signature
address result = ecrecover(hash, v, r, s);

Expand All @@ -44,7 +44,7 @@ library ECVerify {
return result;
}

function ecverify(bytes32 hash, bytes sig, address signer) internal pure returns (bool) {
function ecverify(bytes32 hash, bytes sig, address signer) public pure returns (bool) {
return signer == ecrecovery(hash, sig);
}
}
Loading

0 comments on commit 87243db

Please sign in to comment.