pragma solidity 0.4.24; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "../upgradeability/EternalStorage.sol"; import "./DecimalShiftBridge.sol"; import "./Ownable.sol"; contract BasicTokenBridge is EternalStorage, Ownable, DecimalShiftBridge { using SafeMath for uint256; event DailyLimitChanged(uint256 newLimit); event ExecutionDailyLimitChanged(uint256 newLimit); bytes32 internal constant MIN_PER_TX = 0xbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d1; // keccak256(abi.encodePacked("minPerTx")) bytes32 internal constant MAX_PER_TX = 0x0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c; // keccak256(abi.encodePacked("maxPerTx")) bytes32 internal constant DAILY_LIMIT = 0x4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a5; // keccak256(abi.encodePacked("dailyLimit")) bytes32 internal constant EXECUTION_MAX_PER_TX = 0xc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d5; // keccak256(abi.encodePacked("executionMaxPerTx")) bytes32 internal constant EXECUTION_DAILY_LIMIT = 0x21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d237; // keccak256(abi.encodePacked("executionDailyLimit")) function totalSpentPerDay(uint256 _day) public view returns (uint256) { return uintStorage[keccak256(abi.encodePacked("totalSpentPerDay", _day))]; } function totalExecutedPerDay(uint256 _day) public view returns (uint256) { return uintStorage[keccak256(abi.encodePacked("totalExecutedPerDay", _day))]; } function dailyLimit() public view returns (uint256) { return uintStorage[DAILY_LIMIT]; } function executionDailyLimit() public view returns (uint256) { return uintStorage[EXECUTION_DAILY_LIMIT]; } function maxPerTx() public view returns (uint256) { return uintStorage[MAX_PER_TX]; } function executionMaxPerTx() public view returns (uint256) { return uintStorage[EXECUTION_MAX_PER_TX]; } function minPerTx() public view returns (uint256) { return uintStorage[MIN_PER_TX]; } function withinLimit(uint256 _amount) public view returns (bool) { uint256 nextLimit = totalSpentPerDay(getCurrentDay()).add(_amount); return dailyLimit() >= nextLimit && _amount <= maxPerTx() && _amount >= minPerTx(); } function withinExecutionLimit(uint256 _amount) public view returns (bool) { uint256 nextLimit = totalExecutedPerDay(getCurrentDay()).add(_amount); return executionDailyLimit() >= nextLimit && _amount <= executionMaxPerTx(); } function getCurrentDay() public view returns (uint256) { return now / 1 days; } function addTotalSpentPerDay(uint256 _day, uint256 _value) internal { uintStorage[keccak256(abi.encodePacked("totalSpentPerDay", _day))] = totalSpentPerDay(_day).add(_value); } function addTotalExecutedPerDay(uint256 _day, uint256 _value) internal { uintStorage[keccak256(abi.encodePacked("totalExecutedPerDay", _day))] = totalExecutedPerDay(_day).add(_value); } function setDailyLimit(uint256 _dailyLimit) external onlyOwner { require(_dailyLimit > maxPerTx() || _dailyLimit == 0); uintStorage[DAILY_LIMIT] = _dailyLimit; emit DailyLimitChanged(_dailyLimit); } function setExecutionDailyLimit(uint256 _dailyLimit) external onlyOwner { require(_dailyLimit > executionMaxPerTx() || _dailyLimit == 0); uintStorage[EXECUTION_DAILY_LIMIT] = _dailyLimit; emit ExecutionDailyLimitChanged(_dailyLimit); } function setExecutionMaxPerTx(uint256 _maxPerTx) external onlyOwner { require(_maxPerTx < executionDailyLimit()); uintStorage[EXECUTION_MAX_PER_TX] = _maxPerTx; } function setMaxPerTx(uint256 _maxPerTx) external onlyOwner { require(_maxPerTx == 0 || (_maxPerTx > minPerTx() && _maxPerTx < dailyLimit())); uintStorage[MAX_PER_TX] = _maxPerTx; } function setMinPerTx(uint256 _minPerTx) external onlyOwner { require(_minPerTx > 0 && _minPerTx < dailyLimit() && _minPerTx < maxPerTx()); uintStorage[MIN_PER_TX] = _minPerTx; } /** * @dev Retrieves maximum available bridge amount per one transaction taking into account maxPerTx() and dailyLimit() parameters. * @return minimum of maxPerTx parameter and remaining daily quota. */ function maxAvailablePerTx() public view returns (uint256) { uint256 _maxPerTx = maxPerTx(); uint256 _dailyLimit = dailyLimit(); uint256 _spent = totalSpentPerDay(getCurrentDay()); uint256 _remainingOutOfDaily = _dailyLimit > _spent ? _dailyLimit - _spent : 0; return _maxPerTx < _remainingOutOfDaily ? _maxPerTx : _remainingOutOfDaily; } function _setLimits(uint256[3] _limits) internal { require( _limits[2] > 0 && // minPerTx > 0 _limits[1] > _limits[2] && // maxPerTx > minPerTx _limits[0] > _limits[1] // dailyLimit > maxPerTx ); uintStorage[DAILY_LIMIT] = _limits[0]; uintStorage[MAX_PER_TX] = _limits[1]; uintStorage[MIN_PER_TX] = _limits[2]; emit DailyLimitChanged(_limits[0]); } function _setExecutionLimits(uint256[2] _limits) internal { require(_limits[1] < _limits[0]); // foreignMaxPerTx < foreignDailyLimit uintStorage[EXECUTION_DAILY_LIMIT] = _limits[0]; uintStorage[EXECUTION_MAX_PER_TX] = _limits[1]; emit ExecutionDailyLimitChanged(_limits[0]); } }