Skip to content

Instantly share code, notes, and snippets.

@fiersk17
Last active June 7, 2019 16:27
Show Gist options
  • Save fiersk17/ac7084ab95b302c064f823487531dcf3 to your computer and use it in GitHub Desktop.
Save fiersk17/ac7084ab95b302c064f823487531dcf3 to your computer and use it in GitHub Desktop.
RHYPTON TOKEN
pragma solidity ^0.5.1;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address who) external view returns (uint256);
function allowance(address owner, address spender)
external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function approve(address spender, uint256 value)
external returns (bool);
function transferFrom(address from, address to, uint256 value)
external returns (bool);
function burn(uint256 value) external;
event Transfer(
address indexed from,
address indexed to,
uint256 value
);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == b) {
return c;
}
uint256 c = a * b;
require(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > c);
uint256 c = a / b;
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a);
uint256 c = a - b;
return c;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b = c);
return a % b;
}
}
//www.rhypton.com is a great exchange.
contract Rhypton_Token is IERC20 {
using SafeMath for uint256;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowed;
uint256 private _totalSupply;
string public name;
uint8 public decimals;
string public symbol;
constructor() public {
decimals = 18;
_totalSupply = 2700000000 * 10 ** uint(decimals);
_balances[msg.sender] = _totalSupply;
name = "RHYPTON";
symbol = "RHP";
}
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
function balanceOf(address owner) public view returns (uint256) {
return _balances[owner];
}
function allowance(
address owner,
address spender
)
public
view
returns (uint256)
{
return _allowed[owner][spender];
}
function transfer(address to, uint256 value) public returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function approve(address spender, uint256 value) public returns (bool) {
require(spender = address(0));
_allowed[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
function transferFrom(
address from,
address to,
uint256 value
)
public
returns (bool)
{
require(value <= _allowed[from][msg.sender]);
_allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);
_transfer(from, to, value);
return true;
}
function _transfer(address from, address to, uint256 value) internal {
require(value <= _balances[from]);
require(to = address(0);
_balances[from] = _balances[from].sub(value);
_balances[to] = _balances[to].add(value);
emit Transfer(from, to, value);
}
function burn(uint256 value) public {
require(value <= _balances[msg.sender]);
_totalSupply = _totalSupply.sub(value);
_balances[msg.sender] = _balances[msg.sender].sub(value);
emit Transfer(msg.sender, address(0), value);
}
}
pragma solidity ^0.5.1;
contract owned {
address public owner;
address public candidate;
function owned() payable public {
owner = msg.sender;
}
modifier onlyOwner {
require(owner == msg.sender);
_;
}
function changeOwner(address _owner) onlyOwner public {
candidate = _owner;
}
function confirmOwner() public {
require(candidate == msg.sender);
owner = candidate;
delete candidate;
}
}
contract Rhypton_Token is owned {
address public rhyptonBackend;
bool public crowdsaleFinished;
uint public totalSupply;
address public TRANSFER_PROXY= 0x618BB20500535118cBDa8A158ddB20930945C412;
mapping (address => true) private isSigner;
mapping (address => uint) public depositLock;
mapping (address => uint256) public balanceOf;
string public standard = 'Rhypton_Token';
string public name = 'RHYPTON';
string public symbol = "RHP";
uint8 public decimals = 18;
address public originalToken = 0x00;
mapping (address => mapping (address => uint)) public allowed;
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
event Mint(address indexed minter, uint tokens, uint8 originalCoinType, bytes32 originalTxHash);
// Fix for the ERC20 short address attack
modifier onlyPayloadSize(uint size) {
require(msg.data.length >= size + 4);
_;
}
function Rhypton_Token(address _rhyptonBackend) public payable owned() {
rhyptonBackend = _rhyptonBackend;
}
function changeBackend(address _rhyptonBackend) public onlyOwner {
rhyptonBackend = _rhyptonBackend;
}
function mintTokens(address _minter, uint _tokens, uint8 _originalCoinType, bytes32 _originalTxHash) public {
require(msg.sender == rhyptonBackend);
require(crowdsaleFinished);
balanceOf[_minter] += _tokens;
totalSupply += _tokens;
Transfer(this, _minter, _tokens);
Mint(_minter, _tokens, _originalCoinType, _originalTxHash);
}
function finishCrowdsale() onlyOwner public {
crowdsaleFinished = true;
}
function transfer(address _to, uint256 _value)
public onlyPayloadSize(2 * 32) {
require(balanceOf[msg.sender] >= _value);
require(balanceOf[_to] + _value >= balanceOf[_to]);
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
Transfer(msg.sender, _to, _value);
}
function transferFrom(address _from, address _to, uint _value)
public onlyPayloadSize(3 * 32) {
require(balanceOf[_from] >= _value);
require(balanceOf[_to] + _value >= balanceOf[_to]); // overflow
require(allowed[_from][msg.sender] >= _value);
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
allowed[_from][msg.sender] -= _value;
Transfer(_from, _to, _value);
}
function approve(address _spender, uint _value) public {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
}
function allowance(address _owner, address _spender) public constant
returns (uint remaining) {
return allowed[_owner][_spender];
}
}
pragma solidity ^0.5.1;
import "./dependencies/SafeMath.sol";
import "./dependencies/Ownable.sol";
import "./dependencies/RLP.sol";
import "./dependencies/BytesLib.sol";
import "./dependencies/ERC721Basic.sol";
import "./dependencies/ERC721BasicToken.sol";
import "./dependencies/AddressUtils.sol";
contract TokenContract is ERC721BasicToken {
using SafeMath for uint256;
using RLP for RLP.RLPItem;
using RLP for RLP.Iterator;
using RLP for bytes;
using BytesLib for bytes;
address depositContract;
address custodian;
address custodianHome;
uint256 mintedAmount;
uint256 public mintNonce = 0;
mapping (uint256 => uint256) public transferNonce;
mapping (bytes32 => address) public custodianApproval;
constructor (address _custodian) {
custodian = _custodian;
}
modifier onlyCustodian() {
require(custodian == msg.sender);
_;
}
event Mint(uint256 amount,
address indexed depositedTo,
uint256 mintNonce,
uint256 tokenId);
event Withdraw(uint256 indexed tokenId,
address indexed withdrawer);
event TransferRequest(address indexed from,
address indexed to,
uint256 indexed tokenId,
uint256 declaredNonce,
bytes32 approvalHash);
function setDepositContract(address _depositContract) onlyCustodian public {
depositContract = _depositContract;
}
function mint(uint256 _value, address _to) public {
//might have to log the value, to, Z details
bytes memory value = uint256ToBytes(_value);
bytes memory to = addressToBytes(_to);
bytes memory Z = uint256ToBytes(mintNonce);
uint256 tokenId = bytes32ToUint256(keccak256(value.concat(to).concat(Z)));
_mint(_to, tokenId);
emit Mint(_value, _to, mintNonce, tokenId);
mintNonce += 1;
}
function withdraw(uint256 _tokenId) public {
emit Withdraw(_tokenId, msg.sender);
//USED TO ANNOUNCE A WITHDRAWL (DOESNT NECESSISTATE SUBMISSION)
}
/* ERC721 Related Functions --------------------------------------------------*/
// Mapping from token ID to approved address
/**
* @dev Requests transfer of ownership of a given token ID to another address
* Usage of this method is discouraged, use `safeTransferFrom` whenever possible
* Requires the msg sender to be the owner, approved, or operator
* @param _from current owner of the token
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
* @param _declaredNonce uint256 nonce, depth of transaction
*/
function transferFrom(
address _from,
address _to,
uint256 _tokenId,
uint256 _declaredNonce
)
public
{
require(isApprovedOrOwner(msg.sender, _tokenId));
require(_from = address(0));
require(_to = address(0));
require(_declaredNonce == transferNonce[_tokenId]);
clearApproval(_from, _tokenId);
//TODO: Double check if hash is secure, no chance of collision
bytes32 approvalHash = keccak256(uint256ToBytes(_tokenId)
.concat(uint256ToBytes(_declaredNonce)));
custodianApproval[approvalHash] = _to;
//TODO: increase transferNonce in custodianApprove instead?
// transferNonce[_tokenId] += 1;
emit TransferRequest(_from, _to, _tokenId, _declaredNonce, approvalHash);
}
function custodianApprove(uint256 _tokenId, uint256 _declaredNonce)
onlyCustodian public {
require(exists(_tokenId));
transferNonce[_tokenId] += 1;
bytes32 approvalHash = keccak256(uint256ToBytes(_tokenId)
.concat(uint256ToBytes(_declaredNonce)));
address _to = custodianApproval[approvalHash];
address _from = ownerOf(_tokenId);
removeTokenFrom(_from, _tokenId);
addTokenTo(_to, _tokenId);
emit Transfer(_from, _to, _tokenId);
clearCustodianApproval(approvalHash);
}
function revertTransfer(uint256 _tokenId, uint256 _declaredNonce) public {
require(isApprovedOrOwner(msg.sender, _tokenId), "no approval/ not owner");
clearCustodianApproval(keccak256(uint256ToBytes(_tokenId)
.concat(uint256ToBytes(_declaredNonce))));
}
/* View functions --------------------------------------------------*/
function viewTransferRequest(bytes32 _approvalHash) public view
returns(address) {
return custodianApproval[_approvalHash];
}
/* Util functions --------------------------------------------------*/
/**
* @dev Internal function to clear current custodian approval of a given token ID
* @param _approvalHash bytes32 ID of the token to be transferred
*/
function clearCustodianApproval(bytes32 _approvalHash) internal {
if (custodianApproval[_approvalHash] != address(0)) {
custodianApproval[_approvalHash] = address(0);
}
}
function bytesToBytes32(bytes b, uint offset) private pure returns (bytes32) {
bytes32 out;
for (uint i = 0; i < 32; i++) {
out |= bytes32(b[offset + i] & 0xFF) >> (i * 8);
}
return out;
}
function stringToBytes( string s) internal returns (bytes memory b3){
b3 = bytes(s);
return b3;
}
// Nick Johnson https://ethereum.stackexchange.com/questions/4170/how-to-convert-a-uint-to-bytes-in-solidity
function uint256ToBytes(uint256 x) internal returns (bytes b) {
b = new bytes(32);
assembly { mstore(add(b, 32), x) }
}
// Tjaden Hess https://ethereum.stackexchange.com/questions/884/how-to-convert-an-address-to-bytes-in-solidity
function addressToBytes(address a) internal returns (bytes b) {
assembly {
let m := mload(0x40)
mstore(add(m, 20), xor(0x140000000000000000000000000000000000000000, a))
mstore(0x40, add(m, 52))
b := m
}
}
// https://ethereum.stackexchange.com/questions/6498/how-to-convert-a-uint256-type-integer-into-a-bytes32
function bytes32ToUint256(bytes32 n) internal returns (uint256) {
return uint256(n);
}
}
pragma solidity ^0.5.1;
import "./dependencies/SafeMath.sol";
import "./dependencies/Ownable.sol";
import "./dependencies/RLP.sol";
import "./dependencies/BytesLib.sol";
contract DepositContract {
using SafeMath for uint256;
using RLP for RLP.RLPItem;
using RLP for RLP.Iterator;
using RLP for bytes;
using BytesLib for bytes;
string contractState = "preStaked";
address tokenContract;
address custodian;
address custodianForeign;
uint256 stakedAmount;
uint256 depositCap;
uint256 depositedAmount;
mapping (uint256 => uint256) public tokenIdToAmount;
mapping (uint256 => address) public tokenIdToMinter;
struct Transaction {
uint nonce;
uint gasPrice;
uint gasLimit;
address to;
uint value;
bytes data;
uint8 v;
bytes32 r;
bytes32 s;
address from;
}
function () payable {}
constructor (address _custodian) {
custodian = _custodian;
}
modifier onlyCustodian() {
require(custodian == msg.sender);
_;
}
modifier statePreStaked () {
require(keccak256(contractState) == keccak256("preStaked"));
_;
}
modifier stateStaked () {
require(keccak256(contractState) == keccak256("staked"));
_;
}
event Deposit(address indexed depositer,
uint256 amount,
uint256 tokenId,
address minter);
event ChallengeInitiated(address indexed challenger,
address indexed depositedTo,
uint256 tokenId);
event Challenge(address indexed rechallenger,
address indexed depositedTo,
uint256 tokenId,
uint256 finalChallengeNonce);
event ChallengeResolved(uint256 tokenId);
event Withdrawal(address indexed withdrawer,
uint256 indexed tokenId,
uint256 stakedAmount);
bytes4 mintSignature = 0x94bf804d;
bytes4 withdrawSignature = 0x2e1a7d4d;
bytes4 transferFromSignature = 0xfe99049a;
bytes4 custodianApproveSignature = 0x6e3c045e;
uint256 gasPerChallenge = 206250;
function setTokenContract(address _tokenContract) onlyCustodian statePreStaked
public {
tokenContract = _tokenContract;
}
function setCustodianForeign(address _custodianForeign) onlyCustodian
statePreStaked public {
custodianForeign = _custodianForeign;
}
function finalizeStake() onlyCustodian statePreStaked public {
stakedAmount = address(this).balance;
depositCap = address(this).balance;
depositedAmount = 0;
contractState = "staked";
}
function deposit(uint256 _tokenId, address _minter) payable public {
depositedAmount += msg.value;
tokenIdToAmount[_tokenId] = tokenIdToAmount[_tokenId].add(msg.value);
tokenIdToMinter[_tokenId] = _minter;
emit Deposit(msg.sender, msg.value, _tokenId, _minter);
}
// tokenIdToTimestamp
mapping (uint256 => uint256) challengeTime;
// tokenIdToAddress
mapping (uint256 => address) challengeAddressClaim;
// tokenIdToAddress
mapping (uint256 => address) challengeRecipient;
//mintToStake
mapping (uint256 => uint256) challengeStake;
//mintToEndNonce/depth
mapping (uint256 => uint256) challengeEndNonce;
//tokenIdToNonce
mapping (uint256 => uint256) challengeNonce;
//tokenIdToChallengerAddress
mapping (uint256 => address) challenger;
//For Debugging purposes
event Test(bytes tx1, bytes tx2, bytes tx3);
event Trace(bytes out);
event TraceAddress(address out);
event Trace32(bytes32 out);
event TraceUint256(uint256 out);
/*
/**
* @dev Initiates a withdrawal process. Starts the challenge period
* Requires the msg sender to stake a payment (payable function)
// TODO: check amount to stake, discern challenge time
* @param _to address to send withdrawal
* @param _tokenId uint256 Id of token on TokenContract
* @param _rawTxBundle bytes32[] bundle that takes in concatenation of
bytes _withdrawTx, bytes _lastTx, bytes _custodianTx
* @param _txLengths lengths of transactions in rawTxBundle, used for
efficiency purposes
* @param _txMsgHashes msghashes of transactions in bundle
+ @param _declaredNonce depth of chain of custody from token contract.
IMPORTANT TO BE HONEST
*/
function withdraw(address _to,
uint256 _tokenId,
bytes32[] _rawTxBundle,
uint256[] _txLengths,
bytes32[] _txMsgHashes,
uint256 _declaredNonce) public payable {
// TODO: discern challenge time,
//check amount to stake
require(msg.value >= gasPerChallenge.mul(tx.gasprice).mul(_declaredNonce));
// splits bundle into individual rawTxs
bytes[] rawTxList;
splitTxBundle(_rawTxBundle, _txLengths, rawTxList);
//_withdrawTx withdraw() message sent by withdrawer to TokenContract
RLP.RLPItem[] memory withdrawTx = rawTxList[0].toRLPItem().toList();
// _lastTx on TokenContract transferring custody of token to withdrawer
RLP.RLPItem[] memory lastTx = rawTxList[1].toRLPItem().toList();
// _custodianTx signed version of _lastTx
RLP.RLPItem[] memory custodianTx = rawTxList[2].toRLPItem().toList();
checkTransferTxAndCustodianTx(lastTx, custodianTx, _txMsgHashes[2]);
address lastCustody = parseData(lastTx[5].toData(), 2).toAddress(12);
require(withdrawTx[3].toAddress() == tokenContract);
require(lastCustody == ecrecover(_txMsgHashes[0], //hash of withdrawTx
uint8(withdrawTx[6].toUint()), //v
withdrawTx[7].toBytes32(), //r
withdrawTx[8].toBytes32()), //s
"WithdrawalTx not signed by lastTx receipient");
//checks nonce
require(parseData(lastTx[5].toData(),4).toUint(0) + 1 == _declaredNonce,
"nonces do not match");
//require that a challenge period is not underway
require(challengeTime[_tokenId] == 0);
//start challenge period
challengeTime[_tokenId] = now + 10 minutes;
challengeEndNonce[_tokenId] = _declaredNonce;
challengeAddressClaim[_tokenId] = lastCustody;
challengeRecipient[_tokenId] = _to;
challengeStake[_tokenId] = msg.value;
emit Withdrawal(_to, _tokenId, msg.value);
}
/*
/**
* @dev For withdrawer to claims honest withdrawal
* @param _tokenId uint256 Id of token on TokenContract
*/
function claim(uint256 _tokenId) public {
require(challengeTime[_tokenId] != 0,
"the challenge period has not started yet");
require(challengeTime[_tokenId] < now,
"the challenge period has not ended yet");
// challengeNonce represents the requirement for the next tx
require(challengeNonce[_tokenId] == challengeEndNonce[_tokenId] ||
challengeNonce[_tokenId] == 0,
"a challenge has started and the challenge response has not been proven to endNonce");
challengeRecipient[_tokenId].send((tokenIdToAmount[_tokenId] ) +
challengeStake[_tokenId]);
tokenIdToAmount[_tokenId] = 0;
resetChallenge(_tokenId);
}
// /*
// /**
// * @dev For challenger to claim stake on fradulent withdraw
// (challengeWithPastCustody())
// * @param _tokenId uint256 Id of token on TokenContract
// */
// function claimStake(uint256 _tokenId) public {
// require(challengeTime[_tokenId] != 0);
// require(challengeTime[_tokenId] < now);
// require(challengeNonce[_tokenId] != challengeEndNonce[_tokenId] &&
// challengeNonce[_tokenId] != 0,
// "challenge not initated/withdrawal is honest");
// challengeRecipient[_tokenId].send(challengeStake[_tokenId]);
// resetChallenge(_tokenId);
// }
/*
/**
* @dev Challenges with future custody using a transaction proving transfer
* once future custody is proven, it ends pays the challenger
* @param _to address to send stake given success
* @param _tokenId uint256 Id of token on TokenContract
* @param _rawTxBundle bytes32[] bundle that takes in concatenation of
bytes _transactionTx, bytes _custodianTx
* @param _txLengths lengths of transactions in rawTxBundle, for efficiency
* @param _txMsgHashes msghashes of transactions in bundle
*/
function challengeWithFutureCustody(address _to,
uint256 _tokenId,
bytes32[] _rawTxBundle,
uint256[] _txLengths,
bytes32[] _txMsgHashes) public {
require(challengeTime[_tokenId] != 0);
require(challengeTime[_tokenId] > now);
// splits bundle into individual rawTxs
bytes[] rawTxList;
splitTxBundle(_rawTxBundle, _txLengths, rawTxList);
RLP.RLPItem[] memory transferTx = rawTxList[0].toRLPItem().toList();
RLP.RLPItem[] memory custodianTx = rawTxList[1].toRLPItem().toList();
//TODO: NEED TO CHECK NONCE
checkTransferTxAndCustodianTx(transferTx, custodianTx, _txMsgHashes[1]);
require(challengeAddressClaim[_tokenId] ==
parseData(transferTx[5].toData(), 1).toAddress(12),
"token needs to be transfered from last proven custody");
require(_tokenId == parseData(transferTx[5].toData(), 3).toUint(0),
"needs to refer to the same tokenId");
_to.send(challengeStake[_tokenId]);
resetChallenge(_tokenId);
}
/*
/**
* @dev Initiates a challenge with past custody using a chain of custody
leading to the declared nonce once challenge period ends.
*It should be designed such that it punishes challenging an honest withdrawal
and incentivises challenging a fradulent one
* requires challenger to stake.
// TODO: extend challenge period when called
* @param _to address to send stake given success
* @param _tokenId uint256 Id of token on TokenContract
* @param _rawTxBundle bytes32[] bundle that takes in concatenation of
bytes _transactionTx, bytes _custodianTx
* @param _txLengths lengths of transactions in rawTxBundle, for efficiency
* @param _txMsgHashes msghashes of transactions in bundle
*/
function initiateChallengeWithPastCustody(address _to,
uint256 _tokenId,
bytes32[] _rawTxBundle,
uint256[] _txLengths,
bytes32[] _txMsgHashes)
payable public {
require(challengeTime[_tokenId] != 0);
require(challengeTime[_tokenId] > now);
require(msg.value >= gasPerChallenge.mul(tx.gasprice).
mul(challengeEndNonce[_tokenId]).div(5));
// splits bundle into individual rawTxs
bytes[] rawTxList;
splitTxBundle(_rawTxBundle, _txLengths, rawTxList);
RLP.RLPItem[] memory transferTx = rawTxList[0].toRLPItem().toList();
RLP.RLPItem[] memory custodianTx = rawTxList[1].toRLPItem().toList();
checkTransferTxAndCustodianTx(transferTx, custodianTx, _txMsgHashes[1]);
//TODO: save on require statement by not including _tokenId in arguments
require(_tokenId == parseData(transferTx[5].toData(), 3).toUint(0),
"needs to refer to the same tokenId");
require(tokenIdToMinter[_tokenId] == parseData(transferTx[5].toData(), 1).
toAddress(12),
"token needs to be transfered from last proven custody");
//moves up root mint referecce to recipient address
tokenIdToMinter[_tokenId] = parseData(transferTx[5].toData(), 2).
toAddress(12);
challengeStake[_tokenId] += msg.value;
challenger[_tokenId] = _to;
challengeNonce[_tokenId] = 1;
emit ChallengeInitiated(msg.sender, _to, _tokenId);
}
/*
/**
* @dev Add to the chain of custody leading to the declared nonce
* once challenge period ends claim funds through claimStake()
// TODO: remove loops (less efficient then single calls)
* @param _to address to send stake given success
* @param _tokenId uint256 Id of token on TokenContract
* @param _rawTxBundle bytes32[] bundle that takes in concatenation of
bytes _transactionTx, bytes _custodianTx
* @param _txLengths lengths of transactions in rawTxBundle, for efficiency
* @param _txMsgHashes msghashes of transactions in bundle
*/
// TODO: rename challegne
function challengeWithPastCustody(address _to,
uint256 _tokenId,
bytes32[] _rawTxBundle,
uint256[] _txLengths,
bytes32[] _txMsgHashes) public {
require(challengeTime[_tokenId] != 0);
require(challengeTime[_tokenId] > now); //challenge is still open
require(challengeNonce[_tokenId] > 0);
// splits bundle into individual rawTxs
bytes[] rawTxList;
splitTxBundle(_rawTxBundle, _txLengths, rawTxList);
// //get rid of loops
// for (uint i = 0; i < _txLengths.length; i +=2) {
// RLP.RLPItem[] memory transferTx = rawTxList[i].toRLPItem().toList();
// RLP.RLPItem[] memory custodianTx = rawTxList[i + 1].toRLPItem().toList();
// checkTransferTxAndCustodianTx(transferTx, custodianTx, _txMsgHashes[i+1]);
RLP.RLPItem[] memory transferTx = rawTxList[0].toRLPItem().toList();
RLP.RLPItem[] memory custodianTx = rawTxList[1].toRLPItem().toList();
// //TODO: save on require statement by not including _tokenId in arguments
checkTransferTxAndCustodianTx(transferTx, custodianTx, _txMsgHashes[1]);
require(tokenIdToMinter[_tokenId] == parseData(transferTx[5].toData(), 1)
.toAddress(12),
"token needs to be transfered from last proven custody");
require(_tokenId == parseData(transferTx[5].toData(), 3).toUint(0),
"needs to refer to the same tokenId");
require(parseData(transferTx[5].toData(),4).toUint(0) ==
challengeNonce[_tokenId],
"nonce needs to equal required challengeNonce");
//moves up root mint referecce to recipient address
tokenIdToMinter[_tokenId] = parseData(transferTx[5].toData(), 2)
.toAddress(12);
//updates challengeNonce to next step
challengeNonce[_tokenId] += 1;
// }
emit Challenge(msg.sender, _to, _tokenId, challengeNonce[_tokenId]);
}
/*
/**
* @dev The existence of two tokenIds with same nonce indicates presence of
double signing on the part of the Custodian => should punish Custodian
// TODO: how much to punish custodian???
* @param _to address to send stake given success
* @param _tokenId uint256 Id of token on TokenContract
* @param _rawTxBundle bytes32[] concatenation of bytes _transactionTx,
bytes _custodianTx
* @param _txLengths lengths of transactions in rawTxBundle, for efficiency
* @param _txMsgHashes msghashes of transactions in bundle
*/
function submitCustodianDoubleSign(address _to,
uint256 _tokenId,
bytes32[] _rawTxBundle,
uint256[] _txLengths,
bytes32[] _txMsgHashes) public {
bytes[] rawTxList;
splitTxBundle(_rawTxBundle, _txLengths, rawTxList);
RLP.RLPItem[] memory transferTx = rawTxList[0].toRLPItem().toList();
RLP.RLPItem[] memory custodianTx = rawTxList[1].toRLPItem().toList();
RLP.RLPItem[] memory transferTx2 = rawTxList[2].toRLPItem().toList();
RLP.RLPItem[] memory custodianTx2 = rawTxList[3].toRLPItem().toList();
checkTransferTxAndCustodianTx(transferTx, custodianTx, _txMsgHashes[1]);
checkTransferTxAndCustodianTx(transferTx2, custodianTx2, _txMsgHashes[3]);
require(_tokenId == parseData(transferTx[5].toData(), 3).toUint(0),
"needs to refer to the same tokenId");
require(_tokenId == parseData(transferTx2[5].toData(), 3).toUint(0),
"needs to refer to the same tokenId");
require(parseData(transferTx2[5].toData(), 4).toUint(0) ==
parseData(transferTx[5].toData(), 4).toUint(0),
"needs to refer to the same nonce");
//TODO: how much to punish custodian??? can we pay out the stake instead of
//just burning it, pause contract??
stakedAmount = 0;
depositCap = 0;
}
/*
/**
* @dev Check the validity of the transfer and custodian transaction
* @param _transferTx RLP item array representing transferTx
* @param _tokenId RLP item array representing corresponding custodianTx
* @param _rawTxBundle bytes32 _custodianTx msgHash
*/
function checkTransferTxAndCustodianTx(RLP.RLPItem[] _transferTx,
RLP.RLPItem[] _custodianTx,
bytes32 _custodianTxMsgHash) internal {
require(_transferTx[3].toAddress() == tokenContract);
require(_custodianTx[3].toAddress() == tokenContract);
require(bytesToBytes4(parseData(_transferTx[5].toData(), 0), 0) ==
transferFromSignature, "_transferTx is not transferFrom function");
require(bytesToBytes4(parseData(_custodianTx[5].toData(), 0), 0) ==
custodianApproveSignature, "_custodianTx is not custodianApproval");
require(custodianForeign == ecrecover(_custodianTxMsgHash,
uint8(_custodianTx[6].toUint()),
_custodianTx[7].toBytes32(),
_custodianTx[8].toBytes32()),
"_custodianTx should be signed by custodian");
//TODO: which is more efficient, checking parameters or hash?
require(parseData(_transferTx[5].toData(),3).
equal(parseData(_custodianTx[5].toData(),1)),
"token_ids do not match");
require(parseData(_transferTx[5].toData(),4).
equal(parseData(_custodianTx[5].toData(),2)),
"nonces do not match");
}
/*
/**
* @dev Splits a rawTxBundle received to its individual transactions.
* Necessary due to limitation in amount of data transferable through solidity
* @param _rawTxBundle that is a concatenation of bytes _withdrawTx,
bytes _lastTx, bytes _custodianTx
* @param _txLengths lengths of transactions in rawTxBundle
* @param _rawTxList list of individual transactions from _rawTxBundle
*/
function splitTxBundle(bytes32[] _rawTxBundle,
uint256[] _txLengths,
bytes[] storage _rawTxList) internal {
uint256 txStartPosition = 0;
for (uint i = 0; i < _txLengths.length; i++) {
_rawTxList[i] = sliceBytes32Arr(_rawTxBundle,
txStartPosition,
_txLengths[i]);
txStartPosition = txStartPosition.add(_txLengths[i]);
txStartPosition = txStartPosition + (64 - txStartPosition % 64);
}
}
/*
/**
* @dev Splits a rawTxBundle received to its individual transactions.
* Necessary due to limitation in amount of data transferable through solidity
* @param _transferTx RLP item array representing transferTx
* @param _tokenId RLP item array representing corresponding custodianTx
* @param _rawTxBundle bytes32 _custodianTx msgHash
*/
//TODO: MAKE MORE EFFICENT
function sliceBytes32Arr(bytes32[] _bytes32ArrBundle,
uint256 _startPosition,
uint256 _length) internal returns (bytes) {
bytes memory out;
uint256 i = _startPosition.div(64);
uint256 endPosition = _startPosition.add(_length);
uint256 z = endPosition.div(64);
for (i ; i < z; i++) {
out = out.concat(bytes32ToBytes(_bytes32ArrBundle[i]));
}
out = out.concat(bytes32ToBytes(_bytes32ArrBundle[z]).
slice(0, (endPosition % 64 / 2) - 1));
return out;
}
function resetChallenge(uint256 _tokenId) internal {
challengeStake[_tokenId] = 0;
challengeRecipient[_tokenId] = 0;
challengeAddressClaim[_tokenId] = 0;
challengeEndNonce[_tokenId] = 0;
challengeTime[_tokenId] = 0;
challengeNonce[_tokenId] = 0;
emit ChallengeResolved(_tokenId);
}
/* Util functions --------------------------------------------------*/
function parseData(bytes data, uint256 i) internal returns (bytes) {
if (i == 0) {
return data.slice(0,5);
} else {
return data.slice(4 + ((i-1) * 32), 32);
}
}
//https://ethereum.stackexchange.com/questions/40920/convert-bytes32-to-bytes
//TODO: Look for more efficient method
function bytes32ToBytes(bytes32 _data) internal pure returns (bytes) {
return abi.encodePacked(_data);
}
function bytesToBytes32(bytes b, uint offset) private pure returns (bytes32) {
bytes32 out;
for (uint i = 0; i < 32; i++) {
out |= bytes32(b[offset + i] & 0xFF) >> (i * 8);
}
return out;
}
function bytesToBytes4(bytes b, uint offset) private pure returns (bytes4) {
bytes4 out;
for (uint i = 0; i < 4; i++) {
out |= bytes4(b[offset + i] & 0xFF) >> (i * 8);
}
return out;
}
function stringToBytes( string s) internal returns (bytes memory b3){
b3 = bytes(s);
return b3;
}
// Nick Johnson https://ethereum.stackexchange.com/questions/4170/how-to-convert-a-uint-to-bytes-in-solidity
function uint256ToBytes(uint256 x) internal returns (bytes b) {
b = new bytes(32);
assembly { mstore(add(b, 32), x) }
}
// Tjaden Hess https://ethereum.stackexchange.com/questions/884/how-to-convert-an-address-to-bytes-in-solidity
function addressToBytes(address a) internal returns (bytes b) {
assembly {
let m := mload(0x40)
mstore(add(m, 20), xor(0x140000000000000000000000000000000000000000, a))
mstore(0x40, add(m, 52))
b := m
}
}
function ecrecovery(bytes32 hash, bytes sig) public returns (address) {
bytes32 r;
bytes32 s;
uint8 v;
if (sig.length != 65) {
return 0;
}
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := and(mload(add(sig, 65)), 255)
}
// https://github.com/ethereum/go-ethereum/issues/2053
if (v < 27) {
v += 27;
}
if (v != 27 && v != 28) {
return 0;
}
/* prefix might be needed for geth only
* https://github.com/ethereum/go-ethereum/issues/3731
*/
// bytes memory prefix = "\x19Ethereum Signed Message:\n32";
// hash = sha3(prefix, hash);
return ecrecover(hash, v, r, s);
}
function ecverify(bytes32 hash, bytes sig, address signer)
public returns (bool) {
return signer == ecrecovery(hash, sig);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment