Skip to content

Commit

Permalink
Merge the develop branch to the master branch, preparation to v5.3.1
Browse files Browse the repository at this point in the history
  • Loading branch information
akolotov authored Aug 3, 2020
2 parents 9022354 + 336df6b commit e09bd71
Show file tree
Hide file tree
Showing 20 changed files with 745 additions and 524 deletions.
23 changes: 23 additions & 0 deletions contracts/mocks/PermittableTokenMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
pragma solidity 0.4.24;

import "../PermittableToken.sol";

contract PermittableTokenMock is PermittableToken {
uint256 private _blockTimestamp;

constructor(string _name, string _symbol, uint8 _decimals, uint256 _chainId)
public
PermittableToken(_name, _symbol, _decimals, _chainId)
{
// solhint-disable-previous-line no-empty-blocks
}

function setNow(uint256 _timestamp) public {
_blockTimestamp = _timestamp;
}

function _now() internal view returns (uint256) {
return _blockTimestamp != 0 ? _blockTimestamp : now;
}

}
9 changes: 9 additions & 0 deletions contracts/upgradeable_contracts/BasicAMBMediator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ contract BasicAMBMediator is Ownable {
bytes32 internal constant MEDIATOR_CONTRACT = 0x98aa806e31e94a687a31c65769cb99670064dd7f5a87526da075c5fb4eab9880; // keccak256(abi.encodePacked("mediatorContract"))
bytes32 internal constant REQUEST_GAS_LIMIT = 0x2dfd6c9f781bb6bbb5369c114e949b69ebb440ef3d4dd6b2836225eb1dc3a2be; // keccak256(abi.encodePacked("requestGasLimit"))

/**
* @dev Throws if caller on the other side if not an associated mediator.
*/
modifier onlyMediator {
require(msg.sender == address(bridgeContract()));
require(messageSender() == mediatorContractOnOtherSide());
_;
}

/**
* @dev Sets the AMB bridge contract address. Only the owner can call this method.
* @param _bridgeContract the address of the bridge contract.
Expand Down
8 changes: 2 additions & 6 deletions contracts/upgradeable_contracts/TokenBridgeMediator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ contract TokenBridgeMediator is BasicAMBMediator, BasicTokenBridge, TransferInfo
* @param _recipient address that will receive the tokens
* @param _value amount of tokens to be received
*/
function handleBridgedTokens(address _recipient, uint256 _value) external {
require(msg.sender == address(bridgeContract()));
require(messageSender() == mediatorContractOnOtherSide());
function handleBridgedTokens(address _recipient, uint256 _value) external onlyMediator {
if (withinExecutionLimit(_value)) {
addTotalExecutedPerDay(getCurrentDay(), _value);
executeActionOnBridgedTokens(_recipient, _value);
Expand Down Expand Up @@ -71,9 +69,7 @@ contract TokenBridgeMediator is BasicAMBMediator, BasicTokenBridge, TransferInfo
* It uses the information stored by passMessage method when the assets were initially transferred
* @param _messageId id of the message which execution failed on the other network.
*/
function fixFailedMessage(bytes32 _messageId) external {
require(msg.sender == address(bridgeContract()));
require(messageSender() == mediatorContractOnOtherSide());
function fixFailedMessage(bytes32 _messageId) external onlyMediator {
require(!messageFixed(_messageId));

address recipient = messageRecipient(_messageId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ contract VersionableAMB is VersionableBridge {
* @return (major, minor, patch) version triple
*/
function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
return (5, 0, 2);
return (5, 3, 0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ contract BasicMultiAMBErc20ToErc677 is
* @return patch value of the version
*/
function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
return (1, 0, 0);
return (1, 0, 1);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,14 +266,18 @@ contract BasicMultiTokenBridge is EternalStorage, Ownable {
uint256 _dailyLimit = dailyLimit(address(0)).div(factor);
uint256 _executionMaxPerTx = executionMaxPerTx(address(0)).div(factor);
uint256 _executionDailyLimit = executionDailyLimit(address(0)).div(factor);

// such situation can happen when calculated limits relative to the token decimals are too low
// e.g. minPerTx(address(0)) == 10 ** 14, _decimals == 3. _minPerTx happens to be 0, which is not allowed.
// in this case, limits are raised to the default values
if (_minPerTx == 0) {
_minPerTx = 1;
if (_maxPerTx <= _minPerTx) {
_maxPerTx = 2;
_executionMaxPerTx = 2;
_maxPerTx = 100;
_executionMaxPerTx = 100;
if (_dailyLimit <= _maxPerTx || _executionDailyLimit <= _executionMaxPerTx) {
_dailyLimit = 3;
_executionDailyLimit = 3;
_dailyLimit = 10000;
_executionDailyLimit = 10000;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@ pragma solidity 0.4.24;

import "openzeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol";
import "./BasicMultiAMBErc20ToErc677.sol";
import "./ForeignFeeManagerMultiAMBErc20ToErc677.sol";
import "./HomeMultiAMBErc20ToErc677.sol";
import "../../libraries/TokenReader.sol";

/**
* @title ForeignMultiAMBErc20ToErc677
* @dev Foreign side implementation for multi-erc20-to-erc677 mediator intended to work on top of AMB bridge.
* It is designed to be used as an implementation contract of EternalStorageProxy contract.
*/
contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677, ForeignFeeManagerMultiAMBErc20ToErc677 {
bytes4 internal constant DEPLOY_AND_HANDLE_BRIDGE_TOKENS = 0x2ae87cdd; // deployAndHandleBridgedTokens(address,string,string,uint8,address,uint256)

contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677 {
/**
* @dev Stores the initial parameters of the mediator.
* @param _bridgeContract the address of the AMB bridge contract.
Expand All @@ -23,19 +21,14 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677, ForeignFeeM
* [ 0 = executionDailyLimit, 1 = executionMaxPerTx ]
* @param _requestGasLimit the gas limit for the message execution.
* @param _owner address of the owner of the mediator contract.
* @param _rewardAddreses list of reward addresses, between whom fees will be distributed.
* @param _fees array with initial fees for both bridge firections.
* [ 0 = homeToForeignFee, 1 = foreignToHomeFee ]
*/
function initialize(
address _bridgeContract,
address _mediatorContract,
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256[2] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = _executionDailyLimit, 1 = _executionMaxPerTx ]
uint256 _requestGasLimit,
address _owner,
address[] _rewardAddreses,
uint256[2] _fees // [ 0 = homeToForeignFee, 1 = foreignToHomeFee ]
address _owner
) external onlyRelevantSender returns (bool) {
require(!isInitialized());
require(_owner != address(0));
Expand All @@ -46,11 +39,7 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677, ForeignFeeM
_setExecutionLimits(address(0), _executionDailyLimitExecutionMaxPerTxArray);
_setRequestGasLimit(_requestGasLimit);
setOwner(_owner);
if (_rewardAddreses.length > 0) {
_setRewardAddressList(_rewardAddreses);
}
_setFee(HOME_TO_FOREIGN_FEE, address(0), _fees[0]);
_setFee(FOREIGN_TO_HOME_FEE, address(0), _fees[1]);

setInitialize();

return isInitialized();
Expand All @@ -64,15 +53,9 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677, ForeignFeeM
*/
function executeActionOnBridgedTokens(address _token, address _recipient, uint256 _value) internal {
bytes32 _messageId = messageId();
uint256 valueToTransfer = _value;
uint256 fee = _distributeFee(HOME_TO_FOREIGN_FEE, _token, valueToTransfer);
if (fee > 0) {
emit FeeDistributed(fee, _token, _messageId);
valueToTransfer = valueToTransfer.sub(fee);
}
ERC677(_token).transfer(_recipient, valueToTransfer);
ERC677(_token).transfer(_recipient, _value);
_setMediatorBalance(_token, mediatorBalance(_token).sub(_value));
emit TokensBridged(_token, _recipient, valueToTransfer, _messageId);
emit TokensBridged(_token, _recipient, _value, _messageId);
}

/**
Expand All @@ -89,6 +72,18 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677, ForeignFeeM
return true;
}

/**
* @dev Handles the bridged tokens. Checks that the value is inside the execution limits and invokes the method
* to execute the Mint or Unlock accordingly.
* @param _token bridged ERC20 token.
* @param _recipient address that will receive the tokens.
* @param _value amount of tokens to be received.
*/
function handleBridgedTokens(ERC677 _token, address _recipient, uint256 _value) external onlyMediator {
require(isTokenRegistered(_token));
_handleBridgedTokens(_token, _recipient, _value);
}

/**
* @dev Validates that the token amount is inside the limits, calls transferFrom to transfer the tokens to the contract
* and invokes the method to burn/lock the tokens and unlock/mint the tokens on the other network.
Expand Down Expand Up @@ -130,39 +125,29 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677, ForeignFeeM
require(bytes(name).length > 0 || bytes(symbol).length > 0);

_initializeTokenBridgeLimits(_token, decimals);
_setFee(HOME_TO_FOREIGN_FEE, _token, getFee(HOME_TO_FOREIGN_FEE, address(0)));
_setFee(FOREIGN_TO_HOME_FEE, _token, getFee(FOREIGN_TO_HOME_FEE, address(0)));
}

require(withinLimit(_token, _value));
addTotalSpentPerDay(_token, getCurrentDay(), _value);

bytes memory data;
address receiver = chooseReceiver(_from, _data);
uint256 valueToBridge = _value;
uint256 fee = _distributeFee(FOREIGN_TO_HOME_FEE, _token, valueToBridge);
if (fee > 0) {
emit FeeDistributed(fee, _token, _messageId);
valueToBridge = valueToBridge.sub(fee);
}

if (isKnownToken) {
data = abi.encodeWithSelector(this.handleBridgedTokens.selector, _token, receiver, valueToBridge);
data = abi.encodeWithSelector(this.handleBridgedTokens.selector, _token, receiver, _value);
} else {
data = abi.encodeWithSelector(
DEPLOY_AND_HANDLE_BRIDGE_TOKENS,
HomeMultiAMBErc20ToErc677(this).deployAndHandleBridgedTokens.selector,
_token,
name,
symbol,
decimals,
receiver,
valueToBridge
_value
);
}

// avoid stack too deep error by using existing variable
fee = mediatorBalance(_token).add(valueToBridge);
_setMediatorBalance(_token, fee);
_setMediatorBalance(_token, mediatorBalance(_token).add(_value));

bytes32 _messageId = bridgeContract().requireToPassMessage(
mediatorContractOnOtherSide(),
Expand All @@ -171,8 +156,30 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677, ForeignFeeM
);

setMessageToken(_messageId, _token);
setMessageValue(_messageId, valueToBridge);
setMessageValue(_messageId, _value);
setMessageRecipient(_messageId, _from);

if (!isKnownToken) {
_setTokenRegistrationMessageId(_token, _messageId);
}
}

/**
* @dev Handles the request to fix transferred assets which bridged message execution failed on the other network.
* It uses the information stored by passMessage method when the assets were initially transferred
* @param _messageId id of the message which execution failed on the other network.
*/
function fixFailedMessage(bytes32 _messageId) public {
super.fixFailedMessage(_messageId);
address token = messageToken(_messageId);
if (_messageId == tokenRegistrationMessageId(token)) {
delete uintStorage[keccak256(abi.encodePacked("dailyLimit", token))];
delete uintStorage[keccak256(abi.encodePacked("maxPerTx", token))];
delete uintStorage[keccak256(abi.encodePacked("minPerTx", token))];
delete uintStorage[keccak256(abi.encodePacked("executionDailyLimit", token))];
delete uintStorage[keccak256(abi.encodePacked("executionMaxPerTx", token))];
_setTokenRegistrationMessageId(token, bytes32(0));
}
}

/**
Expand Down Expand Up @@ -228,6 +235,15 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677, ForeignFeeM
return uintStorage[keccak256(abi.encodePacked("mediatorBalance", _token))];
}

/**
* @dev Returns message id where specified token was first seen and deploy on the other side was requested.
* @param _token address of token contract.
* @return message id of the send message.
*/
function tokenRegistrationMessageId(address _token) public view returns (bytes32) {
return bytes32(uintStorage[keccak256(abi.encodePacked("tokenRegistrationMessageId", _token))]);
}

/**
* @dev Updates expected token balance of the contract.
* @param _token address of token contract.
Expand All @@ -236,4 +252,13 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677, ForeignFeeM
function _setMediatorBalance(address _token, uint256 _balance) internal {
uintStorage[keccak256(abi.encodePacked("mediatorBalance", _token))] = _balance;
}

/**
* @dev Updates message id where specified token was first seen and deploy on the other side was requested.
* @param _token address of token contract.
* @param _messageId message id of the send message.
*/
function _setTokenRegistrationMessageId(address _token, bytes32 _messageId) internal {
uintStorage[keccak256(abi.encodePacked("tokenRegistrationMessageId", _token))] = uint256(_messageId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import "./BasicMultiTokenBridge.sol";
import "../BaseRewardAddressList.sol";
import "../Ownable.sol";
import "../../interfaces/ERC677.sol";
import "../../interfaces/IBurnableMintableERC677Token.sol";

/**
* @title ForeignFeeManagerMultiAMBErc20ToErc677
* @title HomeFeeManagerMultiAMBErc20ToErc677
* @dev Implements the logic to distribute fees from the multi erc20 to erc677 mediator contract operations.
* The fees are distributed in the form of native tokens to the list of reward accounts.
*/
contract ForeignFeeManagerMultiAMBErc20ToErc677 is BaseRewardAddressList, Ownable, BasicMultiTokenBridge {
contract HomeFeeManagerMultiAMBErc20ToErc677 is BaseRewardAddressList, Ownable, BasicMultiTokenBridge {
using SafeMath for uint256;

event FeeUpdated(bytes32 feeType, address indexed token, uint256 fee);
Expand Down Expand Up @@ -141,7 +142,11 @@ contract ForeignFeeManagerMultiAMBErc20ToErc677 is BaseRewardAddressList, Ownabl
feeToDistribute = feeToDistribute.add(diff);
}

ERC677(_token).transfer(nextAddr, feeToDistribute);
if (_feeType == HOME_TO_FOREIGN_FEE) {
ERC677(_token).transfer(nextAddr, feeToDistribute);
} else {
IBurnableMintableERC677Token(_token).mint(nextAddr, feeToDistribute);
}

nextAddr = getNextRewardAddress(nextAddr);
require(nextAddr != address(0));
Expand Down
Loading

0 comments on commit e09bd71

Please sign in to comment.