pragma solidity 0.5.16;
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see {ERC20Detailed}.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
pragma solidity 0.5.16;
contract IMorpherState {
function setPosition(
address _address,
bytes32 _marketId,
uint256 _timeStamp,
uint256 _longShares,
uint256 _shortShares,
uint256 _meanEntryPrice,
uint256 _meanEntrySpread,
uint256 _meanEntryLeverage,
uint256 _liquidationPrice
) public;
function getPosition(
address _address,
bytes32 _marketId
) public view returns (
uint256 _longShares,
uint256 _shortShares,
uint256 _meanEntryPrice,
uint256 _meanEntrySpread,
uint256 _meanEntryLeverage,
uint256 _liquidationPrice
);
function getLastUpdated(address _address, bytes32 _marketId) public view returns (uint256 _lastUpdated);
function transfer(address _from, address _to, uint256 _token) public;
function balanceOf(address _tokenOwner) public view returns (uint256 balance);
function mint(address _address, uint256 _token) public;
function burn(address _address, uint256 _token) public;
function getSideChainOperator() public view returns (address _address);
function inactivityPeriod() public view returns (uint256);
function getSideChainMerkleRootWrittenAtTime() public view returns(uint256 _sideChainMerkleRoot);
function fastTransfersEnabled() public view returns(bool);
function mainChain() public view returns(bool);
function setInactivityPeriod(uint256 _periodLength) public;
function disableFastWithdraws() public;
function setSideChainMerkleRoot(bytes32 _sideChainMerkleRoot) public;
function resetLast24HoursAmountWithdrawn() public;
function set24HourWithdrawLimit(uint256 _limit) public;
function getTokenSentToLinkedChain(address _address) public view returns (uint256 _token);
function getTokenClaimedOnThisChain(address _address) public view returns (uint256 _token);
function getTokenSentToLinkedChainTime(address _address) public view returns (uint256 _timeStamp);
function lastWithdrawLimitReductionTime() public view returns (uint256);
function withdrawLimit24Hours() public view returns (uint256);
function update24HoursWithdrawLimit(uint256 _amount) public;
function last24HoursAmountWithdrawn() public view returns (uint256);
function setTokenSentToLinkedChain(address _address, uint256 _token) public;
function setTokenClaimedOnThisChain(address _address, uint256 _token) public;
function add24HoursWithdrawn(uint256 _amount) public;
function getPositionHash(
address _address,
bytes32 _marketId,
uint256 _timeStamp,
uint256 _longShares,
uint256 _shortShares,
uint256 _meanEntryPrice,
uint256 _meanEntrySpread,
uint256 _meanEntryLeverage,
uint256 _liquidationPrice
) public pure returns (bytes32 _hash);
function getPositionClaimedOnMainChain(bytes32 _positionHash) public view returns (bool _alreadyClaimed);
function setPositionClaimedOnMainChain(bytes32 _positionHash) public;
function getBalanceHash(address _address, uint256 _balance) public pure returns (bytes32 _hash);
function getSideChainMerkleRoot() public view returns(bytes32 _sideChainMerkleRoot);
function getBridgeNonce() public returns (uint256 _nonce);
}
pragma solidity 0.5.16;
/**
* @dev These functions deal with verification of Merkle trees (hash trees),
*/
library MerkleProof {
/**
* @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
* defined by `root`. For this, a `proof` must be provided, containing
* sibling hashes on the branch from the leaf to the root of the tree. Each
* pair of leaves and each pair of pre-images are assumed to be sorted.
*/
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
require(proof.length < 100, "MerkleProof: proof too long. Use only sibling hashes.");
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
bytes32 proofElement = proof[i];
if (computedHash < proofElement) {
// Hash(current computed hash + current element of the proof)
computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
} else {
// Hash(current element of the proof + current computed hash)
computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
}
}
// Check if the computed hash (root) is equal to the provided root
return computedHash == root;
}
}
// ------------------------------------------------------------------------
// MorpherBridge
// Handles deposit to and withdraws from the side chain, writing of the merkle
// root to the main chain by the side chain operator, and enforces a rolling 24 hours
// token withdraw limit from side chain to main chain.
// If side chain operator doesn't write a merkle root hash to main chain for more than
// 72 hours positions and balaces from side chain can be transferred to main chain.
// ------------------------------------------------------------------------
pragma solidity 0.5.16;
import "./Ownable.sol";
import "./SafeMath.sol";
import "./IMorpherState.sol";
import "./MerkleProof.sol";
contract MorpherBridge is Ownable {
IMorpherState state;
using SafeMath for uint256;
mapping(address => mapping(uint256 => uint256)) withdrawalPerDay; //[address][day] = withdrawalAmount
mapping(address => mapping(uint256 => uint256)) withdrawalPerMonth; //[address][month] = withdrawalAmount
uint256 public withdrawalLimitDaily = 200000 * (10**18); //200k MPH per day
uint256 public withdrawalLimitMonthly = 1000000 * (10 ** 18); //1M MPH per month
event TransferToLinkedChain(
address indexed from,
uint256 tokens,
uint256 totalTokenSent,
uint256 timeStamp,
uint256 transferNonce,
bytes32 indexed transferHash
);
event TrustlessWithdrawFromSideChain(address indexed from, uint256 tokens);
event OperatorChainTransfer(address indexed from, uint256 tokens, bytes32 sidechainTransactionHash);
event ClaimFailedTransferToSidechain(address indexed from, uint256 tokens);
event PositionRecoveryFromSideChain(address indexed from, bytes32 positionHash);
event TokenRecoveryFromSideChain(address indexed from, bytes32 positionHash);
event SideChainMerkleRootUpdated(bytes32 _rootHash);
event WithdrawLimitReset();
event WithdrawLimitChanged(uint256 _withdrawLimit);
event WithdrawLimitDailyChanged(uint256 _oldLimit, uint256 _newLimit);
event WithdrawLimitMonthlyChanged(uint256 _oldLimit, uint256 _newLimit);
event LinkState(address _address);
constructor(address _stateAddress, address _coldStorageOwnerAddress) public {
setMorpherState(_stateAddress);
transferOwnership(_coldStorageOwnerAddress);
}
modifier onlySideChainOperator {
require(msg.sender == state.getSideChainOperator(), "MorpherBridge: Function can only be called by Sidechain Operator.");
_;
}
modifier sideChainInactive {
require(now - state.inactivityPeriod() > state.getSideChainMerkleRootWrittenAtTime(), "MorpherBridge: Function can only be called if sidechain is inactive.");
_;
}
modifier fastTransfers {
require(state.fastTransfersEnabled() == true, "MorpherBridge: Fast transfers have been disabled permanently.");
_;
}
modifier onlyMainchain {
require(state.mainChain() == true, "MorpherBridge: Function can only be executed on Ethereum." );
_;
}
// ------------------------------------------------------------------------
// Links Token Contract with State
// ------------------------------------------------------------------------
function setMorpherState(address _stateAddress) public onlyOwner {
state = IMorpherState(_stateAddress);
emit LinkState(_stateAddress);
}
function setInactivityPeriod(uint256 _periodInSeconds) private {
state.setInactivityPeriod(_periodInSeconds);
}
function disableFastTransfers() public onlyOwner {
state.disableFastWithdraws();
}
function updateSideChainMerkleRoot(bytes32 _rootHash) public onlySideChainOperator {
state.setSideChainMerkleRoot(_rootHash);
emit SideChainMerkleRootUpdated(_rootHash);
}
function resetLast24HoursAmountWithdrawn() public onlySideChainOperator {
state.resetLast24HoursAmountWithdrawn();
emit WithdrawLimitReset();
}
function set24HourWithdrawLimit(uint256 _withdrawLimit) public onlySideChainOperator {
state.set24HourWithdrawLimit(_withdrawLimit);
emit WithdrawLimitChanged(_withdrawLimit);
}
function updateWithdrawLimitDaily(uint256 _withdrawLimit) public onlySideChainOperator {
emit WithdrawLimitDailyChanged(withdrawalLimitDaily, _withdrawLimit);
withdrawalLimitDaily = _withdrawLimit;
}
function updateWithdrawLimitMonthly(uint256 _withdrawLimit) public onlySideChainOperator {
emit WithdrawLimitMonthlyChanged(withdrawalLimitMonthly, _withdrawLimit);
withdrawalLimitMonthly = _withdrawLimit;
}
function getTokenSentToLinkedChain(address _address) public view returns (uint256 _token) {
return state.getTokenSentToLinkedChain(_address);
}
function getTokenClaimedOnThisChain(address _address) public view returns (uint256 _token) {
return state.getTokenClaimedOnThisChain(_address);
}
function getTokenSentToLinkedChainTime(address _address) public view returns (uint256 _time) {
return state.getTokenSentToLinkedChainTime(_address);
}
// ------------------------------------------------------------------------
// verifyWithdrawOk(uint256 _amount)
// Checks if creating _amount token on main chain does not violate the 24 hour transfer limit
// ------------------------------------------------------------------------
function verifyWithdrawOk(uint256 _amount) public returns (bool _authorized) {
uint256 _lastWithdrawLimitReductionTime = state.lastWithdrawLimitReductionTime();
uint256 _withdrawLimit24Hours = state.withdrawLimit24Hours();
if (now > _lastWithdrawLimitReductionTime) {
uint256 _timePassed = now.sub(_lastWithdrawLimitReductionTime);
state.update24HoursWithdrawLimit(_timePassed.mul(_withdrawLimit24Hours).div(1 days));
}
if (state.last24HoursAmountWithdrawn().add(_amount) <= _withdrawLimit24Hours) {
return true;
} else {
return false;
}
}
function isNotDailyLimitExceeding(uint256 _amount) public view returns(bool) {
return (withdrawalPerDay[msg.sender][block.timestamp / 1 days].add(_amount) <= withdrawalLimitDaily);
}
function isNotMonthlyLimitExceeding(uint256 _amount) public view returns(bool) {
return (withdrawalPerMonth[msg.sender][block.timestamp / 30 days].add(_amount) <= withdrawalLimitMonthly);
}
function verifyUpdateDailyLimit(uint256 _amount) public {
require(isNotDailyLimitExceeding(_amount), "MorpherBridge: Withdrawal Amount exceeds daily limit");
withdrawalPerDay[msg.sender][block.timestamp / 1 days] = withdrawalPerDay[msg.sender][block.timestamp / 1 days].add(_amount);
}
function verifyUpdateMonthlyLimit(uint256 _amount) public {
require(isNotMonthlyLimitExceeding(_amount), "MorpherBridge: Withdrawal Amount exceeds monthly limit");
withdrawalPerMonth[msg.sender][block.timestamp / 30 days] = withdrawalPerMonth[msg.sender][block.timestamp / 30 days].add(_amount);
}
// ------------------------------------------------------------------------
// transferToSideChain(uint256 _tokens)
// Transfer token to Morpher's side chain to trade without fees and near instant
// settlement.
// - Owner's account must have sufficient balance to transfer
// - 0 value transfers are not supported
// Token are burned on the main chain and are created and credited to msg.sender
// on the side chain
// ------------------------------------------------------------------------
function transferToSideChain(uint256 _tokens) public {
require(_tokens >= 0, "MorpherBridge: Amount of tokens must be positive.");
require(state.balanceOf(msg.sender) >= _tokens, "MorpherBridge: Insufficient balance.");
state.burn(msg.sender, _tokens);
uint256 _newTokenSentToLinkedChain = getTokenSentToLinkedChain(msg.sender).add(_tokens);
uint256 _transferNonce = state.getBridgeNonce();
uint256 _timeStamp = now;
bytes32 _transferHash = keccak256(
abi.encodePacked(
msg.sender,
_tokens,
_newTokenSentToLinkedChain,
_timeStamp,
_transferNonce
)
);
state.setTokenSentToLinkedChain(msg.sender, _newTokenSentToLinkedChain);
emit TransferToLinkedChain(msg.sender, _tokens, _newTokenSentToLinkedChain, _timeStamp, _transferNonce, _transferHash);
}
// ------------------------------------------------------------------------
// fastTransferFromSideChain(uint256 _numOfToken, uint256 _tokenBurnedOnLinkedChain, bytes32[] memory _proof)
// The sidechain operator can credit users with token they burend on the sidechain. Transfers
// happen immediately. To be removed after Beta.
// ------------------------------------------------------------------------
function fastTransferFromSideChain(address _address, uint256 _numOfToken, uint256 _tokenBurnedOnLinkedChain, bytes32 _sidechainTransactionHash) public onlySideChainOperator fastTransfers {
uint256 _tokenClaimed = state.getTokenClaimedOnThisChain(_address);
require(verifyWithdrawOk(_numOfToken), "MorpherBridge: Withdraw amount exceeds permitted 24 hour limit. Please try again in a few hours.");
require(_tokenClaimed.add(_numOfToken) <= _tokenBurnedOnLinkedChain, "MorpherBridge: Token amount exceeds token deleted on linked chain.");
_chainTransfer(_address, _tokenClaimed, _numOfToken);
emit OperatorChainTransfer(_address, _numOfToken, _sidechainTransactionHash);
}
// ------------------------------------------------------------------------
// trustlessTransferFromSideChain(uint256 _numOfToken, uint256 _claimLimit, bytes32[] memory _proof)
// Performs a merkle proof on the number of token that have been burned by the user on the side chain.
// If the number of token claimed on the main chain is less than the number of burned token on the side chain
// the difference (or less) can be claimed on the main chain.
// ------------------------------------------------------------------------
function trustlessTransferFromLinkedChain(uint256 _numOfToken, uint256 _claimLimit, bytes32[] memory _proof) public {
bytes32 leaf = keccak256(abi.encodePacked(msg.sender, _claimLimit));
uint256 _tokenClaimed = state.getTokenClaimedOnThisChain(msg.sender);
require(mProof(_proof, leaf), "MorpherBridge: Merkle Proof failed. Please make sure you entered the correct claim limit.");
require(verifyWithdrawOk(_numOfToken), "MorpherBridge: Withdraw amount exceeds permitted 24 hour limit. Please try again in a few hours.");
verifyUpdateDailyLimit(_numOfToken);
verifyUpdateMonthlyLimit(_numOfToken);
require(_tokenClaimed.add(_numOfToken) <= _claimLimit, "MorpherBridge: Token amount exceeds token deleted on linked chain.");
_chainTransfer(msg.sender, _tokenClaimed, _numOfToken);
emit TrustlessWithdrawFromSideChain(msg.sender, _numOfToken);
}
// ------------------------------------------------------------------------
// _chainTransfer(address _address, uint256 _tokenClaimed, uint256 _numOfToken)
// Creates token on the chain for the user after proving their distruction on the
// linked chain has been proven before
// ------------------------------------------------------------------------
function _chainTransfer(address _address, uint256 _tokenClaimed, uint256 _numOfToken) private {
state.setTokenClaimedOnThisChain(_address, _tokenClaimed.add(_numOfToken));
state.add24HoursWithdrawn(_numOfToken);
state.mint(_address, _numOfToken);
}
// ------------------------------------------------------------------------
// claimFailedTransferToSidechain(uint256 _wrongSideChainBalance, bytes32[] memory _proof)
// If token sent to side chain were not credited to the user on the side chain within inactivityPeriod
// they can reclaim the token on the main chain by submitting the proof that their
// side chain balance is less than the number of token sent from main chain.
// ------------------------------------------------------------------------
function claimFailedTransferToSidechain(uint256 _wrongSideChainBalance, bytes32[] memory _proof) public {
bytes32 leaf = keccak256(abi.encodePacked(msg.sender, _wrongSideChainBalance));
uint256 _tokenSentToLinkedChain = getTokenSentToLinkedChain(msg.sender);
uint256 _tokenSentToLinkedChainTime = getTokenSentToLinkedChainTime(msg.sender);
uint256 _inactivityPeriod = state.inactivityPeriod();
require(now > _tokenSentToLinkedChainTime.add(_inactivityPeriod), "MorpherBridge: Failed deposits can only be claimed after inactivity period.");
require(_wrongSideChainBalance < _tokenSentToLinkedChain, "MorpherBridge: Other chain credit is greater equal to wrongSideChainBalance.");
require(verifyWithdrawOk(_tokenSentToLinkedChain.sub(_wrongSideChainBalance)), "MorpherBridge: Claim amount exceeds permitted 24 hour limit.");
require(mProof(_proof, leaf), "MorpherBridge: Merkle Proof failed. Enter total amount of deposits on side chain.");
uint256 _claimAmount = _tokenSentToLinkedChain.sub(_wrongSideChainBalance);
state.setTokenSentToLinkedChain(msg.sender, _tokenSentToLinkedChain.sub(_claimAmount));
state.add24HoursWithdrawn(_claimAmount);
state.mint(msg.sender, _claimAmount);
emit ClaimFailedTransferToSidechain(msg.sender, _claimAmount);
}
// ------------------------------------------------------------------------
// recoverPositionFromSideChain(bytes32[] memory _proof, bytes32 _leaf, bytes32 _marketId, uint256 _timeStamp, uint256 _longShares, uint256 _shortShares, uint256 _meanEntryPrice, uint256 _meanEntrySpread, uint256 _meanEntryLeverage)
// Failsafe against side chain operator becoming inactive or withholding Times (Time withhold attack).
// After 72 hours of no update of the side chain merkle root users can withdraw their last recorded
// positions from side chain to main chain. Overwrites eventually existing position on main chain.
// ------------------------------------------------------------------------
function recoverPositionFromSideChain(
bytes32[] memory _proof,
bytes32 _leaf,
bytes32 _marketId,
uint256 _timeStamp,
uint256 _longShares,
uint256 _shortShares,
uint256 _meanEntryPrice,
uint256 _meanEntrySpread,
uint256 _meanEntryLeverage,
uint256 _liquidationPrice
) public sideChainInactive onlyMainchain {
require(_leaf == state.getPositionHash(msg.sender, _marketId, _timeStamp, _longShares, _shortShares, _meanEntryPrice, _meanEntrySpread, _meanEntryLeverage, _liquidationPrice), "MorpherBridge: leaf does not equal position hash.");
require(state.getPositionClaimedOnMainChain(_leaf) == false, "MorpherBridge: Position already transferred.");
require(mProof(_proof,_leaf) == true, "MorpherBridge: Merkle proof failed.");
state.setPositionClaimedOnMainChain(_leaf);
state.setPosition(msg.sender, _marketId, _timeStamp, _longShares, _shortShares, _meanEntryPrice, _meanEntrySpread, _meanEntryLeverage, _liquidationPrice);
emit PositionRecoveryFromSideChain(msg.sender, _leaf);
// Remark: After resuming operations side chain operator has 72 hours to sync and eliminate transferred positions on side chain to avoid double spend
}
// ------------------------------------------------------------------------
// recoverTokenFromSideChain(bytes32[] memory _proof, bytes32 _leaf, bytes32 _marketId, uint256 _timeStamp, uint256 _longShares, uint256 _shortShares, uint256 _meanEntryPrice, uint256 _meanEntrySpread, uint256 _meanEntryLeverage)
// Failsafe against side chain operator becoming inactive or withholding times (time withhold attack).
// After 72 hours of no update of the side chain merkle root users can withdraw their last recorded
// token balance from side chain to main chain.
// ------------------------------------------------------------------------
function recoverTokenFromSideChain(bytes32[] memory _proof, bytes32 _leaf, uint256 _balance) public sideChainInactive onlyMainchain {
// Require side chain root hash not set on Mainchain for more than 72 hours (=3 days)
require(_leaf == state.getBalanceHash(msg.sender, _balance), "MorpherBridge: Wrong balance.");
require(state.getPositionClaimedOnMainChain(_leaf) == false, "MorpherBridge: Token already transferred.");
require(mProof(_proof,_leaf) == true, "MorpherBridge: Merkle proof failed.");
require(verifyWithdrawOk(_balance), "MorpherBridge: Withdraw amount exceeds permitted 24 hour limit.");
state.setPositionClaimedOnMainChain(_leaf);
_chainTransfer(msg.sender, state.getTokenClaimedOnThisChain(msg.sender), _balance);
emit TokenRecoveryFromSideChain(msg.sender, _leaf);
// Remark: Side chain operator must adjust side chain balances for token recoveries before restarting operations to avoid double spend
}
// ------------------------------------------------------------------------
// mProof(bytes32[] memory _proof, bytes32 _leaf)
// Computes merkle proof against the root hash of the sidechain stored in Morpher state
// ------------------------------------------------------------------------
function mProof(bytes32[] memory _proof, bytes32 _leaf) public view returns(bool _isTrue) {
return MerkleProof.verify(_proof, state.getSideChainMerkleRoot(), _leaf);
}
}
pragma solidity 0.5.16;
import "./IERC20.sol";
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor () internal {
_owner = msg.sender;
emit OwnershipTransferred(address(0), _owner);
}
/**
* @return the address of the owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(isOwner(), "Ownable: caller should be owner.");
_;
}
/**
* @return true if `msg.sender` is the owner of the contract.
*/
function isOwner() public view returns (bool) {
return msg.sender == _owner;
}
/**
* @dev Allows the current owner to relinquish control of the contract.
* It will not be possible to call the functions with the `onlyOwner`
* modifier anymore.
* @notice Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), "Ownable: use renounce ownership instead.");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
// ------------------------------------------------------------------------
// Owner can transfer out any accidentally sent ERC20 tokens
// ------------------------------------------------------------------------
function transferAnyERC20Token(address _tokenAddress, uint256 _tokens) public onlyOwner returns (bool _success) {
return IERC20(_tokenAddress).transfer(owner(), _tokens);
}
}
pragma solidity 0.5.16;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*
* _Available since v2.4.0._
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
{
"compilationTarget": {
"MorpherBridge.sol": "MorpherBridge"
},
"evmVersion": "istanbul",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_stateAddress","type":"address"},{"internalType":"address","name":"_coldStorageOwnerAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"ClaimFailedTransferToSidechain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_address","type":"address"}],"name":"LinkState","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"sidechainTransactionHash","type":"bytes32"}],"name":"OperatorChainTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"bytes32","name":"positionHash","type":"bytes32"}],"name":"PositionRecoveryFromSideChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_rootHash","type":"bytes32"}],"name":"SideChainMerkleRootUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"bytes32","name":"positionHash","type":"bytes32"}],"name":"TokenRecoveryFromSideChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalTokenSent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timeStamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"transferNonce","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"transferHash","type":"bytes32"}],"name":"TransferToLinkedChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"TrustlessWithdrawFromSideChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_withdrawLimit","type":"uint256"}],"name":"WithdrawLimitChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_oldLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newLimit","type":"uint256"}],"name":"WithdrawLimitDailyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_oldLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newLimit","type":"uint256"}],"name":"WithdrawLimitMonthlyChanged","type":"event"},{"anonymous":false,"inputs":[],"name":"WithdrawLimitReset","type":"event"},{"constant":true,"inputs":[],"name":"_owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_wrongSideChainBalance","type":"uint256"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"claimFailedTransferToSidechain","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"disableFastTransfers","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"uint256","name":"_numOfToken","type":"uint256"},{"internalType":"uint256","name":"_tokenBurnedOnLinkedChain","type":"uint256"},{"internalType":"bytes32","name":"_sidechainTransactionHash","type":"bytes32"}],"name":"fastTransferFromSideChain","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"getTokenClaimedOnThisChain","outputs":[{"internalType":"uint256","name":"_token","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"getTokenSentToLinkedChain","outputs":[{"internalType":"uint256","name":"_token","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"getTokenSentToLinkedChainTime","outputs":[{"internalType":"uint256","name":"_time","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"isNotDailyLimitExceeding","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"isNotMonthlyLimitExceeding","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"bytes32","name":"_leaf","type":"bytes32"}],"name":"mProof","outputs":[{"internalType":"bool","name":"_isTrue","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"bytes32","name":"_leaf","type":"bytes32"},{"internalType":"bytes32","name":"_marketId","type":"bytes32"},{"internalType":"uint256","name":"_timeStamp","type":"uint256"},{"internalType":"uint256","name":"_longShares","type":"uint256"},{"internalType":"uint256","name":"_shortShares","type":"uint256"},{"internalType":"uint256","name":"_meanEntryPrice","type":"uint256"},{"internalType":"uint256","name":"_meanEntrySpread","type":"uint256"},{"internalType":"uint256","name":"_meanEntryLeverage","type":"uint256"},{"internalType":"uint256","name":"_liquidationPrice","type":"uint256"}],"name":"recoverPositionFromSideChain","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"bytes32","name":"_leaf","type":"bytes32"},{"internalType":"uint256","name":"_balance","type":"uint256"}],"name":"recoverTokenFromSideChain","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"resetLast24HoursAmountWithdrawn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_withdrawLimit","type":"uint256"}],"name":"set24HourWithdrawLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_stateAddress","type":"address"}],"name":"setMorpherState","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokens","type":"uint256"}],"name":"transferAnyERC20Token","outputs":[{"internalType":"bool","name":"_success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_tokens","type":"uint256"}],"name":"transferToSideChain","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_numOfToken","type":"uint256"},{"internalType":"uint256","name":"_claimLimit","type":"uint256"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"trustlessTransferFromLinkedChain","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"_rootHash","type":"bytes32"}],"name":"updateSideChainMerkleRoot","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_withdrawLimit","type":"uint256"}],"name":"updateWithdrawLimitDaily","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_withdrawLimit","type":"uint256"}],"name":"updateWithdrawLimitMonthly","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"verifyUpdateDailyLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"verifyUpdateMonthlyLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"verifyWithdrawOk","outputs":[{"internalType":"bool","name":"_authorized","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"withdrawalLimitDaily","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"withdrawalLimitMonthly","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]