Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support negative decimal shift #448

Merged
merged 3 commits into from Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc
Expand Up @@ -23,6 +23,7 @@
"no-use-before-define": ["error", { "functions": false }],
"no-restricted-syntax": "off",
"node/no-unpublished-require": "off",
"func-names": "off"
"func-names": "off",
"no-loop-func": "off"
}
}
8 changes: 2 additions & 6 deletions contracts/upgradeable_contracts/BasicTokenBridge.sol
Expand Up @@ -2,9 +2,10 @@ 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 {
contract BasicTokenBridge is EternalStorage, Ownable, DecimalShiftBridge {
using SafeMath for uint256;

event DailyLimitChanged(uint256 newLimit);
Expand All @@ -15,7 +16,6 @@ contract BasicTokenBridge is EternalStorage, Ownable {
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"))
bytes32 internal constant DECIMAL_SHIFT = 0x1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee5; // keccak256(abi.encodePacked("decimalShift"))

function totalSpentPerDay(uint256 _day) public view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("totalSpentPerDay", _day))];
Expand Down Expand Up @@ -45,10 +45,6 @@ contract BasicTokenBridge is EternalStorage, Ownable {
return uintStorage[MIN_PER_TX];
}

function decimalShift() public view returns (uint256) {
return uintStorage[DECIMAL_SHIFT];
}

function withinLimit(uint256 _amount) public view returns (bool) {
uint256 nextLimit = totalSpentPerDay(getCurrentDay()).add(_amount);
return dailyLimit() >= nextLimit && _amount <= maxPerTx() && _amount >= minPerTx();
Expand Down
64 changes: 64 additions & 0 deletions contracts/upgradeable_contracts/DecimalShiftBridge.sol
@@ -0,0 +1,64 @@
pragma solidity 0.4.24;

import "../upgradeability/EternalStorage.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";

contract DecimalShiftBridge is EternalStorage {
using SafeMath for uint256;

bytes32 internal constant DECIMAL_SHIFT = 0x1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee5; // keccak256(abi.encodePacked("decimalShift"))

/**
* @dev Internal function for setting the decimal shift for bridge operations.
* Decimal shift can be positive, negative, or equal to zero.
* It has the following meaning: N tokens in the foreign chain are equivalent to N * pow(10, shift) tokens on the home side.
* @param _shift new value of decimal shift.
*/
function _setDecimalShift(int256 _shift) internal {
// since 1 wei * 10**77 > 2**255, it does not make any sense to use higher values
require(_shift > -77 && _shift < 77);
uintStorage[DECIMAL_SHIFT] = uint256(_shift);
}

/**
* @dev Returns the value of foreign-to-home decimal shift.
* @return decimal shift.
*/
function decimalShift() public view returns (int256) {
return int256(uintStorage[DECIMAL_SHIFT]);
}

/**
* @dev Converts the amount of home tokens into the equivalent amount of foreign tokens.
* @param _value amount of home tokens.
* @return equivalent amount of foreign tokens.
*/
function _unshiftValue(uint256 _value) internal view returns (uint256) {
return _shiftUint(_value, -decimalShift());
}

/**
* @dev Converts the amount of foreign tokens into the equivalent amount of home tokens.
* @param _value amount of foreign tokens.
* @return equivalent amount of home tokens.
*/
function _shiftValue(uint256 _value) internal view returns (uint256) {
return _shiftUint(_value, decimalShift());
}

/**
* @dev Calculates _value * pow(10, _shift).
* @param _value amount of tokens.
* @param _shift decimal shift to apply.
* @return shifted value.
*/
function _shiftUint(uint256 _value, int256 _shift) private pure returns (uint256) {
if (_shift == 0) {
return _value;
}
if (_shift > 0) {
return _value.mul(10**uint256(_shift));
}
return _value.div(10**uint256(-_shift));
}
}
Expand Up @@ -29,7 +29,7 @@ contract BasicAMBErc20ToNative is Initializable, Upgradeable, Claimable, Version
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = dailyLimit, 1 = maxPerTx, 2 = minPerTx ]
uint256[2] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = executionDailyLimit, 1 = executionMaxPerTx ]
uint256 _requestGasLimit,
uint256 _decimalShift,
int256 _decimalShift,
address _owner
) internal {
require(!isInitialized());
Expand All @@ -49,7 +49,7 @@ contract BasicAMBErc20ToNative is Initializable, Upgradeable, Claimable, Version
uintStorage[MIN_PER_TX] = _dailyLimitMaxPerTxMinPerTxArray[2];
uintStorage[EXECUTION_DAILY_LIMIT] = _executionDailyLimitExecutionMaxPerTxArray[0];
uintStorage[EXECUTION_MAX_PER_TX] = _executionDailyLimitExecutionMaxPerTxArray[1];
uintStorage[DECIMAL_SHIFT] = _decimalShift;
_setDecimalShift(_decimalShift);
setOwner(_owner);

emit DailyLimitChanged(_dailyLimitMaxPerTxMinPerTxArray[0]);
Expand Down
Expand Up @@ -31,7 +31,7 @@ contract ForeignAMBErc20ToNative is BasicAMBErc20ToNative, ReentrancyGuard, Base
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = dailyLimit, 1 = maxPerTx, 2 = minPerTx ]
uint256[2] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = executionDailyLimit, 1 = executionMaxPerTx ]
uint256 _requestGasLimit,
uint256 _decimalShift,
int256 _decimalShift,
address _owner,
address _erc677token
) external onlyRelevantSender returns (bool) {
Expand Down Expand Up @@ -139,7 +139,7 @@ contract ForeignAMBErc20ToNative is BasicAMBErc20ToNative, ReentrancyGuard, Base
* @param _value amount of tokens to be received
*/
function executeActionOnBridgedTokens(address _receiver, uint256 _value) internal {
uint256 valueToTransfer = _value.div(10**decimalShift());
uint256 valueToTransfer = _unshiftValue(_value);
bytes32 _messageId = messageId();

_setMediatorBalance(mediatorBalance().sub(valueToTransfer));
Expand Down
Expand Up @@ -31,7 +31,7 @@ contract HomeAMBErc20ToNative is BasicAMBErc20ToNative, BlockRewardBridge, HomeF
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = dailyLimit, 1 = maxPerTx, 2 = minPerTx ]
uint256[2] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = executionDailyLimit, 1 = executionMaxPerTx ]
uint256 _requestGasLimit,
uint256 _decimalShift,
int256 _decimalShift,
address _owner,
address _blockReward
) public onlyRelevantSender returns (bool) {
Expand Down Expand Up @@ -71,7 +71,7 @@ contract HomeAMBErc20ToNative is BasicAMBErc20ToNative, BlockRewardBridge, HomeF
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = dailyLimit, 1 = maxPerTx, 2 = minPerTx ]
uint256[2] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = executionDailyLimit, 1 = executionMaxPerTx ]
uint256 _requestGasLimit,
uint256 _decimalShift,
int256 _decimalShift,
address _owner,
address _blockReward,
address[] _rewardAddreses,
Expand Down Expand Up @@ -177,7 +177,7 @@ contract HomeAMBErc20ToNative is BasicAMBErc20ToNative, BlockRewardBridge, HomeF
* @param _value amount of native tokens to be received
*/
function executeActionOnBridgedTokens(address _receiver, uint256 _value) internal {
uint256 valueToMint = _value.mul(10**decimalShift());
uint256 valueToMint = _shiftValue(_value);
bytes32 _messageId = messageId();

uint256 fee = _distributeFee(FOREIGN_TO_HOME_FEE, valueToMint);
Expand Down
Expand Up @@ -32,7 +32,7 @@ contract BasicAMBErc677ToErc677 is
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256[2] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = _executionDailyLimit, 1 = _executionMaxPerTx ]
uint256 _requestGasLimit,
uint256 _decimalShift,
int256 _decimalShift,
address _owner
) public onlyRelevantSender returns (bool) {
require(!isInitialized());
Expand All @@ -52,7 +52,7 @@ contract BasicAMBErc677ToErc677 is
uintStorage[EXECUTION_DAILY_LIMIT] = _executionDailyLimitExecutionMaxPerTxArray[0];
uintStorage[EXECUTION_MAX_PER_TX] = _executionDailyLimitExecutionMaxPerTxArray[1];
_setRequestGasLimit(_requestGasLimit);
uintStorage[DECIMAL_SHIFT] = _decimalShift;
_setDecimalShift(_decimalShift);
setOwner(_owner);
setInitialize();

Expand Down
Expand Up @@ -14,7 +14,7 @@ contract ForeignAMBErc677ToErc677 is BasicAMBErc677ToErc677 {
* @param _value amount of bridged tokens
*/
function executeActionOnBridgedTokens(address _recipient, uint256 _value) internal {
uint256 value = _value.div(10**decimalShift());
uint256 value = _unshiftValue(_value);
bytes32 _messageId = messageId();
erc677token().transfer(_recipient, value);
emit TokensBridged(_recipient, value, _messageId);
Expand Down
Expand Up @@ -15,7 +15,7 @@ contract ForeignStakeTokenMediator is BasicStakeTokenMediator {
* @param _value amount of bridged tokens
*/
function executeActionOnBridgedTokens(address _recipient, uint256 _value) internal {
uint256 value = _value.div(10**decimalShift());
uint256 value = _unshiftValue(_value);
bytes32 _messageId = messageId();
_transferWithOptionalMint(_recipient, value);
emit TokensBridged(_recipient, value, _messageId);
Expand Down
Expand Up @@ -15,7 +15,7 @@ contract HomeAMBErc677ToErc677 is BasicAMBErc677ToErc677 {
* @param _value amount of bridged tokens
*/
function executeActionOnBridgedTokens(address _recipient, uint256 _value) internal {
uint256 value = _value.mul(10**decimalShift());
uint256 value = _shiftValue(_value);
bytes32 _messageId = messageId();
IBurnableMintableERC677Token(erc677token()).mint(_recipient, value);
emit TokensBridged(_recipient, value, _messageId);
Expand Down
Expand Up @@ -21,7 +21,7 @@ contract HomeStakeTokenMediator is BasicStakeTokenMediator, HomeStakeTokenFeeMan
* @param _dailyLimitMaxPerTxMinPerTxArray Home limits for outgoing transfers
* @param _executionDailyLimitExecutionMaxPerTxArray Home execution limits for incoming transfers
* @param _requestGasLimit gas limit used for AMB operations
* @param _decimalShift decimal shift for bridged TAKE token
* @param _decimalShift decimal shift for bridged STAKE token
* @param _owner address of new bridge owner
*/
function initialize(
Expand All @@ -31,7 +31,7 @@ contract HomeStakeTokenMediator is BasicStakeTokenMediator, HomeStakeTokenFeeMan
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256[2] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = _executionDailyLimit, 1 = _executionMaxPerTx ]
uint256 _requestGasLimit,
uint256 _decimalShift,
int256 _decimalShift,
address _owner
) public returns (bool) {
addressStorage[MINT_HANDLER] = _erc677token;
Expand All @@ -56,7 +56,7 @@ contract HomeStakeTokenMediator is BasicStakeTokenMediator, HomeStakeTokenFeeMan
* @param _dailyLimitMaxPerTxMinPerTxArray Home limits for outgoing transfers
* @param _executionDailyLimitExecutionMaxPerTxArray Home execution limits for incoming transfers
* @param _requestGasLimit gas limit used for AMB operations
* @param _decimalShift decimal shift for bridged TAKE token
* @param _decimalShift decimal shift for bridged STAKE token
* @param _owner address of new bridge owner
* @param _blockReward address of block reward contract used for fee distribution
* @param _fee initial home fee
Expand All @@ -68,7 +68,7 @@ contract HomeStakeTokenMediator is BasicStakeTokenMediator, HomeStakeTokenFeeMan
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256[2] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = _executionDailyLimit, 1 = _executionMaxPerTx ]
uint256 _requestGasLimit,
uint256 _decimalShift,
int256 _decimalShift,
address _owner,
address _blockReward,
uint256 _fee
Expand Down Expand Up @@ -122,7 +122,7 @@ contract HomeStakeTokenMediator is BasicStakeTokenMediator, HomeStakeTokenFeeMan
* @param _value amount of bridged tokens
*/
function executeActionOnBridgedTokens(address _recipient, uint256 _value) internal {
uint256 value = _value.mul(10**decimalShift());
uint256 value = _shiftValue(_value);
bytes32 _messageId = messageId();
getMintHandler().mint(_recipient, value);
emit TokensBridged(_recipient, value, _messageId);
Expand Down
Expand Up @@ -38,7 +38,7 @@ contract BasicAMBNativeToErc20 is
uint256[3] _dailyLimitMaxPerTxMinPerTxArray,
uint256[2] _executionDailyLimitExecutionMaxPerTxArray,
uint256 _requestGasLimit,
uint256 _decimalShift,
int256 _decimalShift,
address _owner,
address _feeManager
) internal {
Expand All @@ -59,7 +59,7 @@ contract BasicAMBNativeToErc20 is
uintStorage[MIN_PER_TX] = _dailyLimitMaxPerTxMinPerTxArray[2];
uintStorage[EXECUTION_DAILY_LIMIT] = _executionDailyLimitExecutionMaxPerTxArray[0];
uintStorage[EXECUTION_MAX_PER_TX] = _executionDailyLimitExecutionMaxPerTxArray[1];
uintStorage[DECIMAL_SHIFT] = _decimalShift;
_setDecimalShift(_decimalShift);
_setFeeManagerContract(_feeManager);
setOwner(_owner);

Expand Down
Expand Up @@ -32,7 +32,7 @@ contract ForeignAMBNativeToErc20 is BasicAMBNativeToErc20, ReentrancyGuard, Base
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = dailyLimit, 1 = maxPerTx, 2 = minPerTx ]
uint256[2] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = executionDailyLimit, 1 = executionMaxPerTx ]
uint256 _requestGasLimit,
uint256 _decimalShift,
int256 _decimalShift,
address _owner,
address _erc677token,
address _feeManager
Expand Down Expand Up @@ -67,7 +67,7 @@ contract ForeignAMBNativeToErc20 is BasicAMBNativeToErc20, ReentrancyGuard, Base
* @param _value amount of tokens to be received
*/
function executeActionOnBridgedTokens(address _receiver, uint256 _value) internal {
uint256 valueToMint = _value.div(10**decimalShift());
uint256 valueToMint = _unshiftValue(_value);

bytes32 _messageId = messageId();
IMediatorFeeManager feeManager = feeManagerContract();
Expand Down
Expand Up @@ -29,7 +29,7 @@ contract HomeAMBNativeToErc20 is BasicAMBNativeToErc20 {
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = dailyLimit, 1 = maxPerTx, 2 = minPerTx ]
uint256[2] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = executionDailyLimit, 1 = executionMaxPerTx ]
uint256 _requestGasLimit,
uint256 _decimalShift,
int256 _decimalShift,
address _owner,
address _feeManager
) external onlyRelevantSender returns (bool) {
Expand Down Expand Up @@ -84,7 +84,7 @@ contract HomeAMBNativeToErc20 is BasicAMBNativeToErc20 {
* @param _value amount of native tokens to be received
*/
function executeActionOnBridgedTokens(address _receiver, uint256 _value) internal {
uint256 valueToTransfer = _value.mul(10**decimalShift());
uint256 valueToTransfer = _shiftValue(_value);
setMediatorBalance(mediatorBalance().sub(valueToTransfer));

bytes32 _messageId = messageId();
Expand Down
Expand Up @@ -12,7 +12,7 @@ contract BasicForeignBridgeErcToErc is BasicForeignBridge {
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256[2] _homeDailyLimitHomeMaxPerTxArray, // [ 0 = _homeDailyLimit, 1 = _homeMaxPerTx ]
address _owner,
uint256 _decimalShift
int256 _decimalShift
) internal {
require(!isInitialized());
require(AddressUtils.isContract(_validatorContract));
Expand All @@ -35,7 +35,7 @@ contract BasicForeignBridgeErcToErc is BasicForeignBridge {
uintStorage[MIN_PER_TX] = _dailyLimitMaxPerTxMinPerTxArray[2];
uintStorage[EXECUTION_DAILY_LIMIT] = _homeDailyLimitHomeMaxPerTxArray[0];
uintStorage[EXECUTION_MAX_PER_TX] = _homeDailyLimitHomeMaxPerTxArray[1];
uintStorage[DECIMAL_SHIFT] = _decimalShift;
_setDecimalShift(_decimalShift);
setOwner(_owner);
setInitialize();

Expand All @@ -59,7 +59,7 @@ contract BasicForeignBridgeErcToErc is BasicForeignBridge {
bytes32 /*_txHash*/
) internal returns (bool) {
setTotalExecutedPerDay(getCurrentDay(), totalExecutedPerDay(getCurrentDay()).add(_amount));
uint256 amount = _amount.div(10**decimalShift());
uint256 amount = _unshiftValue(_amount);
return erc20token().transfer(_recipient, amount);
}

Expand Down
Expand Up @@ -12,7 +12,7 @@ contract ForeignBridgeErc677ToErc677 is ERC677Bridge, BasicForeignBridgeErcToErc
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256[2] _homeDailyLimitHomeMaxPerTxArray, // [ 0 = _homeDailyLimit, 1 = _homeMaxPerTx ]
address _owner,
uint256 _decimalShift
int256 _decimalShift
) external onlyRelevantSender returns (bool) {
_initialize(
_validatorContract,
Expand Down
Expand Up @@ -12,7 +12,7 @@ contract ForeignBridgeErcToErc is BasicForeignBridgeErcToErc, ERC20Bridge {
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256[2] _homeDailyLimitHomeMaxPerTxArray, // [ 0 = _homeDailyLimit, 1 = _homeMaxPerTx ]
address _owner,
uint256 _decimalShift
int256 _decimalShift
) external onlyRelevantSender returns (bool) {
_initialize(
_validatorContract,
Expand Down