contract BiLinkExchange is Ownable {

	using SafeMath for uint256;



	address public contractBalance;

	uint256 public commissionRatio;//percentage



	mapping (address => mapping ( bytes32 => uint256)) public account2Order2TradeAmount;



	bool public isLegacy;//if true, not allow new trade,new deposit



	event OnTrade(address tokenGive, address tokenGet, address maker, address taker, uint256 amountGive, uint256 amountGet, uint256 amountGetTrade, uint256 timestamp);

	



	constructor(address _owner, uint256 _commissionRatio) public Ownable(_owner) {

		isLegacy= false;

		commissionRatio= _commissionRatio;

	}



	function setThisContractAsLegacy() public onlyOwner {

		isLegacy= true;

	}



	function setBalanceContract(address _contractBalance) public onlyOwner {

		contractBalance= _contractBalance;

	}



	//_arr1:tokenGive,tokenGet,maker,taker

	//_arr2:amountGive,amountGet,amountGetTrade,expireTime

	//_arr3:rMaker,sMaker,rTaker,sTaker

	//parameters are from taker's perspective

	function trade(address[] _arr1, uint256[] _arr2, uint8 _vMaker,uint8 _vTaker, bytes32[] _arr3) public {

		require(isLegacy== false&& now <= _arr2[3]);



		uint256 _amountTokenGiveTrade= _arr2[0].mul(_arr2[2]).div(_arr2[1]);

		require(_arr2[2]<= IBalance(contractBalance).getAvailableBalance(_arr1[1], _arr1[2])&&_amountTokenGiveTrade<= IBalance(contractBalance).getAvailableBalance(_arr1[0], _arr1[3]));



		bytes32 _hash = keccak256(abi.encodePacked(this, _arr1[1], _arr1[0], _arr2[1], _arr2[0], _arr2[3]));

		require(ecrecover(_hash, _vMaker, _arr3[0], _arr3[1]) ==  _arr1[2]

			&& ecrecover(keccak256(abi.encodePacked(this, _arr1[0], _arr1[1], _arr2[0], _arr2[1], _arr2[2], _arr1[2], _arr2[3])), _vTaker, _arr3[2], _arr3[3]) ==  _arr1[3]

			&& account2Order2TradeAmount[_arr1[2]][_hash].add(_arr2[2])<= _arr2[1]);



		uint256 _commission= _arr2[2].mul(commissionRatio).div(10000);

		

		IBalance(contractBalance).modifyBalance(_arr1[3], _arr1[1], _arr2[2].sub(_commission), true);

		IBalance(contractBalance).modifyBalance(_arr1[2], _arr1[1], _arr2[2], false); 

		

		IBalance(contractBalance).modifyBalance(_arr1[3], _arr1[0], _amountTokenGiveTrade, false);

		IBalance(contractBalance).modifyBalance(_arr1[2], _arr1[0], _amountTokenGiveTrade, true);

		account2Order2TradeAmount[_arr1[2]][_hash]= account2Order2TradeAmount[_arr1[2]][_hash].add(_arr2[2]);

						

		if(_arr1[1]== address(0)) {

			IBalance(contractBalance).distributeEthProfit(_arr1[3], _commission);

		}

		else {

			IBalance(contractBalance).distributeTokenProfit(_arr1[3], _arr1[1], _commission);

		}



		emit OnTrade(_arr1[0], _arr1[1], _arr1[2], _arr1[3], _arr2[0], _arr2[1], _arr2[2], now);

	}

}
function trade(address[] _arr1, uint256[] _arr2, uint8 _vMaker,uint8 _vTaker, bytes32[] _arr3) public {

	require(isLegacy== false&& now <= _arr2[3]);



	uint256 _amountTokenGiveTrade= _arr2[0].mul(_arr2[2]).div(_arr2[1]);

	require(_arr2[2]<= IBalance(contractBalance).getAvailableBalance(_arr1[1], _arr1[2])&&_amountTokenGiveTrade<= IBalance(contractBalance).getAvailableBalance(_arr1[0], _arr1[3]));



	bytes32 _hash = keccak256(abi.encodePacked(this, _arr1[1], _arr1[0], _arr2[1], _arr2[0], _arr2[3]));

	require(ecrecover(_hash, _vMaker, _arr3[0], _arr3[1]) ==  _arr1[2]

		&& ecrecover(keccak256(abi.encodePacked(this, _arr1[0], _arr1[1], _arr2[0], _arr2[1], _arr2[2], _arr1[2], _arr2[3])), _vTaker, _arr3[2], _arr3[3]) ==  _arr1[3]

		&& account2Order2TradeAmount[_arr1[2]][_hash].add(_arr2[2])<= _arr2[1]);



	uint256 _commission= _arr2[2].mul(commissionRatio).div(10000);

		

	IBalance(contractBalance).modifyBalance(_arr1[3], _arr1[1], _arr2[2].sub(_commission), true);

	IBalance(contractBalance).modifyBalance(_arr1[2], _arr1[1], _arr2[2], false); 

		

	IBalance(contractBalance).modifyBalance(_arr1[3], _arr1[0], _amountTokenGiveTrade, false);

	IBalance(contractBalance).modifyBalance(_arr1[2], _arr1[0], _amountTokenGiveTrade, true);

	account2Order2TradeAmount[_arr1[2]][_hash]= account2Order2TradeAmount[_arr1[2]][_hash].add(_arr2[2]);

						

	if(_arr1[1]== address(0)) {

		IBalance(contractBalance).distributeEthProfit(_arr1[3], _commission);

	}

	else {

		IBalance(contractBalance).distributeTokenProfit(_arr1[3], _arr1[1], _commission);

	}



	emit OnTrade(_arr1[0], _arr1[1], _arr1[2], _arr1[3], _arr2[0], _arr2[1], _arr2[2], now);

}

//_arr1:tokenGive,tokenGet,maker,taker
//_arr2:amountGive,amountGet,amountGetTrade,expireTime
//_arr3:rMaker,sMaker,rTaker,sTaker
//parameters are from taker's perspective