pragma solidity ^0.4.24; // import 'openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol'; // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v1.12.0/contracts/token/ERC20/StandardToken.sol // https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v1.12.0/contracts/token/ERC20 library SafeMath { function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) { if (_a == 0) {return 0;} c = _a * _b; assert(c / _a == _b); return c; } function div(uint256 _a, uint256 _b) internal pure returns (uint256) {return _a / _b;} function sub(uint256 _a, uint256 _b) internal pure returns (uint256) { assert(_b <= _a); return _a - _b; } function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) { c = _a + _b; assert(c >= _a); return c; } } library ExtendedMath { function limitLessThan(uint a, uint b) internal pure returns (uint c) { if(a > b) return b; return a; } } // ---------------------------------------------------------------------------- // ERC Token Standard #20 Interface // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md // ---------------------------------------------------------------------------- // /* contract ERC20Interface { //function totalSupply() public constant returns (uint); //function balanceOf(address tokenOwner) public constant returns (uint balance); //function allowance(address tokenOwner, address spender) public constant returns (uint remaining); function transfer(address to, uint tokens) public returns (bool success); //function approve(address spender, uint tokens) public returns (bool success); //function transferFrom(address from, address to, uint tokens) public returns (bool success); event Transfer(address indexed from, address indexed to, uint tokens); //event Approval(address indexed tokenOwner, address indexed spender, uint tokens); } // */ contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address _who) public view returns (uint256); function transfer(address _to, uint256 _value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } contract BasicToken is ERC20Basic { using SafeMath for uint256; mapping(address => uint256) internal balances; uint256 internal totalSupply_; function totalSupply() public view returns (uint256) {return totalSupply_;} function transfer(address _to, uint256 _value) public returns (bool) { require(_value <= balances[msg.sender]); require(_to != address(0)); balances[msg.sender] = balances[msg.sender].sub(_value); balances[_to] = balances[_to].add(_value); emit Transfer(msg.sender, _to, _value); return true; } function balanceOf(address _owner) public view returns (uint256) {return balances[_owner];} } contract ERC20 is ERC20Basic { function allowance(address _owner, address _spender) public view returns (uint256); function transferFrom(address _from, address _to, uint256 _value) public returns (bool); function approve(address _spender, uint256 _value) public returns (bool); event Approval(address indexed owner, address indexed spender, uint256 value); } contract StandardToken is ERC20, BasicToken { mapping (address => mapping (address => uint256)) internal allowed; function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { require(_value <= balances[_from]); require(_value <= allowed[_from][msg.sender]); require(_to != address(0)); balances[_from] = balances[_from].sub(_value); balances[_to] = balances[_to].add(_value); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); emit Transfer(_from, _to, _value); return true; } function approve(address _spender, uint256 _value) public returns (bool) { allowed[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } function allowance(address _owner, address _spender) public view returns (uint256) {return allowed[_owner][_spender];} function increaseApproval(address _spender, uint256 _addedValue) public returns (bool) { allowed[msg.sender][_spender] = ( allowed[msg.sender][_spender].add(_addedValue)); emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true; } function decreaseApproval(address _spender, uint256 _subtractedValue) public returns (bool){ uint256 oldValue = allowed[msg.sender][_spender]; if (_subtractedValue >= oldValue) { allowed[msg.sender][_spender] = 0; } else { allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); } emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true; } } contract ApproveAndCallFallBack { function receiveApproval(address from, uint256 tokens, address token, bytes data) public; } contract Ownable { address private _owner; event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); constructor() internal { _owner = msg.sender; emit OwnershipTransferred(address(0), _owner); } function owner() public view returns(address) {return _owner;} modifier onlyOwner() { require(isOwner()); _; } function isOwner() public view returns(bool) {return msg.sender == _owner;} function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } function transferOwnership(address newOwner) public onlyOwner {_transferOwnership(newOwner);} function _transferOwnership(address newOwner) internal { require(newOwner != address(0)); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } contract SignatureUtils { function toEthBytes32SignedMessageHash(bytes32 _msg) pure public returns (bytes32 signHash) { signHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _msg)); } function toEthPersonalSignedMessageHash(bytes _msg) pure public returns (bytes32 signHash) { signHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", uintToString(_msg.length), _msg)); } function uintToString(uint v) pure public returns (string) { uint w = v; bytes32 x; if (v == 0) { x = "0"; } else { while (w > 0) { x = bytes32(uint(x) / (2 ** 8)); x |= bytes32(((w % 10) + 48) * 2 ** (8 * 31)); w /= 10; } } bytes memory bytesString = new bytes(32); uint charCount = 0; for (uint j = 0; j < 32; j++) { byte char = byte(bytes32(uint(x) * 2 ** (8 * j))); if (char != 0) { bytesString[charCount] = char; charCount++; } } bytes memory resultBytes = new bytes(charCount); for (j = 0; j < charCount; j++) { resultBytes[j] = bytesString[j]; } return string(resultBytes); } function parseSignature(bytes _signatures, uint _pos) pure public returns (uint8 v, bytes32 r, bytes32 s) { uint offset = _pos * 65; assembly { // solium-disable-line security/no-inline-assembly r := mload(add(_signatures, add(32, offset))) s := mload(add(_signatures, add(64, offset))) v := and(mload(add(_signatures, add(65, offset))), 0xff) } if (v < 27) v += 27; require(v == 27 || v == 28); } function countSignatures(bytes _signatures) pure public returns (uint) { return _signatures.length % 65 == 0 ? _signatures.length / 65 : 0; } function recoverAddress(bytes32 _hash, bytes _signatures, uint _pos) pure public returns (address) { uint8 v; bytes32 r; bytes32 s; (v, r, s) = parseSignature(_signatures, _pos); return ecrecover(_hash, v, r, s); } function recoverAddresses(bytes32 _hash, bytes _signatures) pure public returns (address[] addresses) { uint8 v; bytes32 r; bytes32 s; uint count = countSignatures(_signatures); addresses = new address[](count); for (uint i = 0; i < count; i++) { (v, r, s) = parseSignature(_signatures, i); addresses[i] = ecrecover(_hash, v, r, s); } } } contract Bridgeable is StandardToken, SignatureUtils, Ownable { address[] public validators; address public foreignContract; mapping (bytes32 => bool) foreignTransactions; event EnterBridgeEvent(address from, uint256 amount); event ExitBridgeEvent(address sender, uint256 amount); event Mint(address indexed to, uint256 amount); event Burn(address indexed burner, uint256 value); function addValidator(address _validator) public onlyOwner {validators.push(_validator);} function pair(address _foreignContract) public onlyOwner {foreignContract = _foreignContract;} function enter(uint256 _amount) public { emit EnterBridgeEvent(msg.sender, _amount); burn(_amount); } function exit(bytes32 _txnHash, address _foreignContract, uint256 _amount, bytes _signatures) public { require(contains(_txnHash) == false, 'Foreign transaction has already been processed'); bytes32 hash = toEthBytes32SignedMessageHash(entranceHash(_txnHash,_foreignContract, _amount)); address[] memory recovered = recoverAddresses(hash, _signatures); require(verifyValidators(recovered), "Validator verification failed."); require(_foreignContract == foreignContract, "Invalid contract target."); mint(msg.sender, _amount); foreignTransactions[_txnHash] = true; emit ExitBridgeEvent(msg.sender, _amount); } function contains(bytes32 _txnHash) internal view returns (bool){return foreignTransactions[_txnHash];} function verifyValidators(address[] recovered) internal view returns (bool) { require(recovered.length == validators.length, "Invalid number of signatures"); for(uint i = 0 ; i < validators.length; i++) { if(validators[i] != recovered[i]) { return false; } } return true; } function mint(address _to, uint256 _amount ) internal returns (bool) { totalSupply_ = totalSupply_.add(_amount); balances[_to] = balances[_to].add(_amount); emit Mint(_to, _amount); emit Transfer(address(0), _to, _amount); return true; } function burn(uint256 _value) internal {_burn(msg.sender, _value);} function _burn(address _who, uint256 _value) internal { require(_value <= balances[_who]); balances[_who] = balances[_who].sub(_value); totalSupply_ = totalSupply_.sub(_value); emit Burn(_who, _value); emit Transfer(_who, address(0), _value); } function entranceHash(bytes32 txnHash, address _contractAddress, uint256 _amount) public view returns (bytes32) { return keccak256(abi.encode( bytes4(0x8177cf3c), msg.sender, txnHash, _contractAddress, _amount)); } function approveAndCall(address spender, uint tokens, bytes data) public returns (bool success) { allowed[msg.sender][spender] = tokens; emit Approval(msg.sender, spender, tokens); ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, this, data); return true; } function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) { return ERC20Interface(tokenAddress).transfer(owner, tokens); } } contract HomeToken is Bridgeable { using SafeMath for uint; using ExtendedMath for uint; string public name = "Home Token"; string public symbol = "HTOK"; uint public decimals = 18; uint public INITIAL_SUPPLY = 0; constructor() public { totalSupply_ = 210000000 * (10 ** decimals); balances[msg.sender] = 0; // no pre-mine } }
0.4.24