Skip to content

Commit

Permalink
Add erc-to-native mediators (#440)
Browse files Browse the repository at this point in the history
  • Loading branch information
k1rill-fedoseev committed Jun 30, 2020
1 parent a90ce6c commit de50e60
Show file tree
Hide file tree
Showing 41 changed files with 4,063 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity 0.4.24;
import "../interfaces/IBlockReward.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";

contract BlockReward {
contract BlockRewardMock {
using SafeMath for uint256;

event BridgeTokenRewardAdded(uint256 amount, uint256 cumulativeAmount, address indexed bridge);
Expand Down
24 changes: 24 additions & 0 deletions contracts/mocks/BlockRewardWithoutSystem.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pragma solidity ^0.4.24;

import "../upgradeable_contracts/amb_erc20_to_native/BlockReward.sol";

contract BlockRewardWithoutSystem is BlockReward {
address public bridgeContractAddress;

modifier onlySystem {
_;
}

modifier onlyBridgeContract {
_;
}

function setBridgeContractAddress(address _addr) external {
bridgeContractAddress = _addr;
}

function bridgesAllowed() public view returns (address[bridgesAllowedLength]) {
// These values must be changed before deploy
return [address(bridgeContractAddress)];
}
}
4 changes: 2 additions & 2 deletions contracts/upgradeable_contracts/BaseERC677Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "./ERC677Storage.sol";
import "../libraries/Bytes.sol";

contract BaseERC677Bridge is BasicTokenBridge, ERC677Receiver, ERC677Storage {
function erc677token() public view returns (ERC677) {
function _erc677token() internal view returns (ERC677) {
return ERC677(addressStorage[ERC677_TOKEN]);
}

Expand All @@ -18,7 +18,7 @@ contract BaseERC677Bridge is BasicTokenBridge, ERC677Receiver, ERC677Storage {
}

function onTokenTransfer(address _from, uint256 _value, bytes _data) external returns (bool) {
ERC677 token = erc677token();
ERC677 token = _erc677token();
require(msg.sender == address(token));
require(withinLimit(_value));
setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(_value));
Expand Down
147 changes: 147 additions & 0 deletions contracts/upgradeable_contracts/BaseRewardAddressList.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
pragma solidity 0.4.24;

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

/**
* @title BaseRewardAddressList
* @dev Implements the logic to store, add and remove reward account addresses. Works as a linked list.
*/
contract BaseRewardAddressList is EternalStorage {
using SafeMath for uint256;

address public constant F_ADDR = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;
uint256 internal constant MAX_REWARD_ADDRESSES = 50;
bytes32 internal constant REWARD_ADDRESS_COUNT = 0xabc77c82721ced73eef2645facebe8c30249e6ac372cce6eb9d1fed31bd6648f; // keccak256(abi.encodePacked("rewardAddressCount"))

event RewardAddressAdded(address indexed addr);
event RewardAddressRemoved(address indexed addr);

/**
* @dev Retrieves all registered reward accounts.
* @return address list of the registered reward receivers.
*/
function rewardAddressList() external view returns (address[]) {
address[] memory list = new address[](rewardAddressCount());
uint256 counter = 0;
address nextAddr = getNextRewardAddress(F_ADDR);

while (nextAddr != F_ADDR) {
require(nextAddr != address(0));

list[counter] = nextAddr;
nextAddr = getNextRewardAddress(nextAddr);
counter++;
}

return list;
}

/**
* @dev Retrieves amount of registered reward accounts.
* @return length of reward addresses list.
*/
function rewardAddressCount() public view returns (uint256) {
return uintStorage[REWARD_ADDRESS_COUNT];
}

/**
* @dev Checks if specified address is included into the registered rewards receivers list.
* @param _addr address to verify.
* @return true, if specified address is associated with one of the registered reward accounts.
*/
function isRewardAddress(address _addr) public view returns (bool) {
return _addr != F_ADDR && getNextRewardAddress(_addr) != address(0);
}

/**
* @dev Retrieves next reward address in the linked list, or F_ADDR if given address is the last one.
* @param _address address of some reward account.
* @return address of the next reward receiver.
*/
function getNextRewardAddress(address _address) public view returns (address) {
return addressStorage[keccak256(abi.encodePacked("rewardAddressList", _address))];
}

/**
* @dev Internal function for adding a new reward address to the linked list.
* @param _addr new reward account.
*/
function _addRewardAddress(address _addr) internal {
require(_addr != address(0) && _addr != F_ADDR);
require(!isRewardAddress(_addr));

address nextAddr = getNextRewardAddress(F_ADDR);

require(nextAddr != address(0));

_setNextRewardAddress(_addr, nextAddr);
_setNextRewardAddress(F_ADDR, _addr);
_setRewardAddressCount(rewardAddressCount().add(1));
}

/**
* @dev Internal function for removing existing reward address from the linked list.
* @param _addr old reward account which should be removed.
*/
function _removeRewardAddress(address _addr) internal {
require(isRewardAddress(_addr));
address nextAddr = getNextRewardAddress(_addr);
address index = F_ADDR;
address next = getNextRewardAddress(index);

while (next != _addr) {
require(next != address(0));
index = next;
next = getNextRewardAddress(index);
require(next != F_ADDR);
}

_setNextRewardAddress(index, nextAddr);
delete addressStorage[keccak256(abi.encodePacked("rewardAddressList", _addr))];
_setRewardAddressCount(rewardAddressCount().sub(1));
}

/**
* @dev Internal function for initializing linked list with the array of the initial reward addresses.
* @param _rewardAddresses initial reward addresses list, should be non-empty.
*/
function _setRewardAddressList(address[] _rewardAddresses) internal {
require(_rewardAddresses.length > 0);

_setNextRewardAddress(F_ADDR, _rewardAddresses[0]);

for (uint256 i = 0; i < _rewardAddresses.length; i++) {
require(_rewardAddresses[i] != address(0) && _rewardAddresses[i] != F_ADDR);
require(!isRewardAddress(_rewardAddresses[i]));

if (i == _rewardAddresses.length - 1) {
_setNextRewardAddress(_rewardAddresses[i], F_ADDR);
} else {
_setNextRewardAddress(_rewardAddresses[i], _rewardAddresses[i + 1]);
}

emit RewardAddressAdded(_rewardAddresses[i]);
}

_setRewardAddressCount(_rewardAddresses.length);
}

/**
* @dev Internal function for updating the length of the reward accounts list.
* @param _rewardAddressCount new linked list length.
*/
function _setRewardAddressCount(uint256 _rewardAddressCount) internal {
require(_rewardAddressCount <= MAX_REWARD_ADDRESSES);
uintStorage[REWARD_ADDRESS_COUNT] = _rewardAddressCount;
}

/**
* @dev Internal function for updating the pointer to the next reward receiver.
* @param _prevAddr address of some reward receiver.
* @param _addr address of the next receiver to which _prevAddr should point to.
*/
function _setNextRewardAddress(address _prevAddr, address _addr) internal {
addressStorage[keccak256(abi.encodePacked("rewardAddressList", _prevAddr))] = _addr;
}
}
17 changes: 14 additions & 3 deletions contracts/upgradeable_contracts/BasicBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ contract BasicBridge is InitializableBridge, Validatable, Ownable, Upgradeable,
bytes32 internal constant GAS_PRICE = 0x55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b; // keccak256(abi.encodePacked("gasPrice"))
bytes32 internal constant REQUIRED_BLOCK_CONFIRMATIONS = 0x916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d79407230071; // keccak256(abi.encodePacked("requiredBlockConfirmations"))

/**
* @dev Public setter for fallback gas price value. Only bridge owner can call this method.
* @param _gasPrice new value for the gas price.
*/
function setGasPrice(uint256 _gasPrice) external onlyOwner {
require(_gasPrice > 0);
uintStorage[GAS_PRICE] = _gasPrice;
emit GasPriceChanged(_gasPrice);
_setGasPrice(_gasPrice);
}

function gasPrice() external view returns (uint256) {
Expand All @@ -38,4 +40,13 @@ contract BasicBridge is InitializableBridge, Validatable, Ownable, Upgradeable,
function claimTokens(address _token, address _to) public onlyIfUpgradeabilityOwner validAddress(_to) {
claimValues(_token, _to);
}

/**
* @dev Internal function for updating fallback gas price value.
* @param _gasPrice new value for the gas price, zero gas price is allowed.
*/
function _setGasPrice(uint256 _gasPrice) internal {
uintStorage[GAS_PRICE] = _gasPrice;
emit GasPriceChanged(_gasPrice);
}
}
9 changes: 9 additions & 0 deletions contracts/upgradeable_contracts/BasicForeignBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ contract BasicForeignBridge is EternalStorage, Validatable, BasicBridge, BasicTo
}
}

/**
* @dev Internal function for updating fallback gas price value.
* @param _gasPrice new value for the gas price, zero gas price is not allowed.
*/
function _setGasPrice(uint256 _gasPrice) internal {
require(_gasPrice > 0);
super._setGasPrice(_gasPrice);
}

/* solcov ignore next */
function onExecuteMessage(address, uint256, bytes32) internal returns (bool);

Expand Down
4 changes: 4 additions & 0 deletions contracts/upgradeable_contracts/ERC677Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import "./BaseERC677Bridge.sol";
import "./OtherSideBridgeStorage.sol";

contract ERC677Bridge is BaseERC677Bridge, OtherSideBridgeStorage {
function erc677token() public view returns (ERC677) {
return _erc677token();
}

function bridgeSpecificActionsOnTokenTransfer(
ERC677, /*_token*/
address _from,
Expand Down
8 changes: 8 additions & 0 deletions contracts/upgradeable_contracts/RewardableMediator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ contract RewardableMediator is Ownable {
* @param _feeManager the address of the fee manager contract.
*/
function setFeeManagerContract(address _feeManager) external onlyOwner {
_setFeeManagerContract(_feeManager);
}

/**
* @dev Internal function for enabling new / disabling fee manage contract.
* @param _feeManager the address of the fee manager contract.
*/
function _setFeeManagerContract(address _feeManager) internal {
require(_feeManager == address(0) || AddressUtils.isContract(_feeManager));
addressStorage[FEE_MANAGER_CONTRACT] = _feeManager;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
pragma solidity 0.4.24;

import "../Initializable.sol";
import "../Upgradeable.sol";
import "../Claimable.sol";
import "../VersionableBridge.sol";
import "../TokenBridgeMediator.sol";

/**
* @title BasicAMBErc20ToNative
* @dev Common mediator functionality for erc20-to-native bridge intended to work on top of AMB bridge.
*/
contract BasicAMBErc20ToNative is Initializable, Upgradeable, Claimable, VersionableBridge, TokenBridgeMediator {
/**
* @dev Stores the initial parameters of the mediator.
* @param _bridgeContract the address of the AMB bridge contract.
* @param _mediatorContract the address of the mediator contract on the other network.
* @param _dailyLimitMaxPerTxMinPerTxArray array with limit values for the assets to be bridged to the other network.
* [ 0 = dailyLimit, 1 = maxPerTx, 2 = minPerTx ]
* @param _executionDailyLimitExecutionMaxPerTxArray array with limit values for the assets bridged from the other network.
* [ 0 = executionDailyLimit, 1 = executionMaxPerTx ]
* @param _requestGasLimit the gas limit for the message execution.
* @param _decimalShift number of decimals shift required to adjust the amount of tokens bridged.
* @param _owner address of the owner of the mediator contract
*/
function _initialize(
address _bridgeContract,
address _mediatorContract,
uint256[] _dailyLimitMaxPerTxMinPerTxArray,
uint256[] _executionDailyLimitExecutionMaxPerTxArray,
uint256 _requestGasLimit,
uint256 _decimalShift,
address _owner
) internal {
require(!isInitialized());
require(
_dailyLimitMaxPerTxMinPerTxArray[2] > 0 && // minPerTx > 0
_dailyLimitMaxPerTxMinPerTxArray[1] > _dailyLimitMaxPerTxMinPerTxArray[2] && // maxPerTx > minPerTx
_dailyLimitMaxPerTxMinPerTxArray[0] > _dailyLimitMaxPerTxMinPerTxArray[1] // dailyLimit > maxPerTx
);
require(_executionDailyLimitExecutionMaxPerTxArray[1] < _executionDailyLimitExecutionMaxPerTxArray[0]); // foreignMaxPerTx < foreignDailyLimit
require(_owner != address(0));

_setBridgeContract(_bridgeContract);
_setMediatorContractOnOtherSide(_mediatorContract);
_setRequestGasLimit(_requestGasLimit);
uintStorage[DAILY_LIMIT] = _dailyLimitMaxPerTxMinPerTxArray[0];
uintStorage[MAX_PER_TX] = _dailyLimitMaxPerTxMinPerTxArray[1];
uintStorage[MIN_PER_TX] = _dailyLimitMaxPerTxMinPerTxArray[2];
uintStorage[EXECUTION_DAILY_LIMIT] = _executionDailyLimitExecutionMaxPerTxArray[0];
uintStorage[EXECUTION_MAX_PER_TX] = _executionDailyLimitExecutionMaxPerTxArray[1];
uintStorage[DECIMAL_SHIFT] = _decimalShift;
setOwner(_owner);

emit DailyLimitChanged(_dailyLimitMaxPerTxMinPerTxArray[0]);
emit ExecutionDailyLimitChanged(_executionDailyLimitExecutionMaxPerTxArray[0]);
}

/**
* @dev Tells the bridge interface version that this contract supports.
* @return major value of the version
* @return minor value of the version
* @return patch value of the version
*/
function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
return (1, 0, 0);
}

/**
* @dev Tells the bridge mode that this contract supports.
* @return _data 4 bytes representing the bridge mode
*/
function getBridgeMode() external pure returns (bytes4 _data) {
return 0xe177c00f; // bytes4(keccak256(abi.encodePacked("erc-to-native-amb")))
}

/**
* @dev Execute the action to be performed when the bridge tokens are out of execution limits.
*/
function executeActionOnBridgedTokensOutOfLimit(
address, /* _recipient */
uint256 /* _value */
) internal {
revert();
}
}
Loading

0 comments on commit de50e60

Please sign in to comment.