144 lines
6.4 KiB
Solidity
144 lines
6.4 KiB
Solidity
pragma solidity 0.4.24;
|
|
|
|
import "openzeppelin-solidity/contracts/AddressUtils.sol";
|
|
import "./Ownable.sol";
|
|
import "./FeeTypes.sol";
|
|
|
|
/**
|
|
* @title RewardableBridge
|
|
* @dev Common functionality for fee management logic delegation to the separate fee management contract.
|
|
*/
|
|
contract RewardableBridge is Ownable, FeeTypes {
|
|
event FeeDistributedFromAffirmation(uint256 feeAmount, bytes32 indexed transactionHash);
|
|
event FeeDistributedFromSignatures(uint256 feeAmount, bytes32 indexed transactionHash);
|
|
|
|
bytes32 internal constant FEE_MANAGER_CONTRACT = 0x779a349c5bee7817f04c960f525ee3e2f2516078c38c68a3149787976ee837e5; // keccak256(abi.encodePacked("feeManagerContract"))
|
|
bytes4 internal constant GET_HOME_FEE = 0x94da17cd; // getHomeFee()
|
|
bytes4 internal constant GET_FOREIGN_FEE = 0xffd66196; // getForeignFee()
|
|
bytes4 internal constant GET_FEE_MANAGER_MODE = 0xf2ba9561; // getFeeManagerMode()
|
|
bytes4 internal constant SET_HOME_FEE = 0x34a9e148; // setHomeFee(uint256)
|
|
bytes4 internal constant SET_FOREIGN_FEE = 0x286c4066; // setForeignFee(uint256)
|
|
bytes4 internal constant CALCULATE_FEE = 0x9862f26f; // calculateFee(uint256,bool,bytes32)
|
|
bytes4 internal constant DISTRIBUTE_FEE_FROM_SIGNATURES = 0x59d78464; // distributeFeeFromSignatures(uint256)
|
|
bytes4 internal constant DISTRIBUTE_FEE_FROM_AFFIRMATION = 0x054d46ec; // distributeFeeFromAffirmation(uint256)
|
|
|
|
/**
|
|
* @dev Internal function for reading the fee value from the fee manager.
|
|
* @param _feeType type of the fee, should be either HOME_FEE of FOREIGN_FEE.
|
|
* @return retrieved fee percentage.
|
|
*/
|
|
function _getFee(bytes32 _feeType) internal view validFeeType(_feeType) returns (uint256 fee) {
|
|
address feeManager = feeManagerContract();
|
|
bytes4 method = _feeType == HOME_FEE ? GET_HOME_FEE : GET_FOREIGN_FEE;
|
|
bytes memory callData = abi.encodeWithSelector(method);
|
|
|
|
assembly {
|
|
let result := delegatecall(gas, feeManager, add(callData, 0x20), mload(callData), 0, 32)
|
|
|
|
if and(eq(returndatasize, 32), result) {
|
|
fee := mload(0)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @dev Retrieves the mode of the used fee manager.
|
|
* @return manager mode identifier, or zero bytes otherwise.
|
|
*/
|
|
function getFeeManagerMode() external view returns (bytes4 mode) {
|
|
bytes memory callData = abi.encodeWithSelector(GET_FEE_MANAGER_MODE);
|
|
address feeManager = feeManagerContract();
|
|
assembly {
|
|
let result := delegatecall(gas, feeManager, add(callData, 0x20), mload(callData), 0, 4)
|
|
|
|
if and(eq(returndatasize, 32), result) {
|
|
mode := mload(0)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @dev Retrieves the address of the fee manager contract used.
|
|
* @return address of the fee manager contract.
|
|
*/
|
|
function feeManagerContract() public view returns (address) {
|
|
return addressStorage[FEE_MANAGER_CONTRACT];
|
|
}
|
|
|
|
/**
|
|
* @dev Updates the address of the used fee manager contract.
|
|
* Only contract owner can call this method.
|
|
* If during this operation, home fee is changed, it is highly recommended to stop the bridge operations first.
|
|
* Otherwise, pending signature requests can become a reason for imbalance between two bridge sides.
|
|
* @param _feeManager address of the new fee manager contract, or zero address to disable fee collection.
|
|
*/
|
|
function setFeeManagerContract(address _feeManager) external onlyOwner {
|
|
require(_feeManager == address(0) || AddressUtils.isContract(_feeManager));
|
|
addressStorage[FEE_MANAGER_CONTRACT] = _feeManager;
|
|
}
|
|
|
|
/**
|
|
* @dev Internal function for setting the fee value by using the fee manager.
|
|
* @param _feeManager address of the fee manager contract.
|
|
* @param _fee new value for fee percentage amount.
|
|
* @param _feeType type of the fee, should be either HOME_FEE of FOREIGN_FEE.
|
|
*/
|
|
function _setFee(address _feeManager, uint256 _fee, bytes32 _feeType) internal validFeeType(_feeType) {
|
|
bytes4 method = _feeType == HOME_FEE ? SET_HOME_FEE : SET_FOREIGN_FEE;
|
|
require(_feeManager.delegatecall(abi.encodeWithSelector(method, _fee)));
|
|
}
|
|
|
|
/**
|
|
* @dev Calculates the exact fee amount by using the fee manager.
|
|
* @param _value transferred value for which fee should be calculated.
|
|
* @param _recover true, if the fee was already subtracted from the given _value and needs to be restored.
|
|
* @param _impl address of the fee manager contract.
|
|
* @param _feeType type of the fee, should be either HOME_FEE of FOREIGN_FEE.
|
|
* @return calculated fee amount.
|
|
*/
|
|
function calculateFee(uint256 _value, bool _recover, address _impl, bytes32 _feeType)
|
|
internal
|
|
view
|
|
returns (uint256 fee)
|
|
{
|
|
bytes memory callData = abi.encodeWithSelector(CALCULATE_FEE, _value, _recover, _feeType);
|
|
assembly {
|
|
let result := callcode(gas, _impl, 0x0, add(callData, 0x20), mload(callData), 0, 32)
|
|
|
|
switch and(eq(returndatasize, 32), result)
|
|
case 1 {
|
|
fee := mload(0)
|
|
}
|
|
default {
|
|
revert(0, 0)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @dev Internal function for distributing the fee for collecting sufficient amount of signatures.
|
|
* @param _fee amount of fee to distribute.
|
|
* @param _feeManager address of the fee manager contract.
|
|
* @param _txHash reference transaction hash where the original bridge request happened.
|
|
*/
|
|
function distributeFeeFromSignatures(uint256 _fee, address _feeManager, bytes32 _txHash) internal {
|
|
if (_fee > 0) {
|
|
require(_feeManager.delegatecall(abi.encodeWithSelector(DISTRIBUTE_FEE_FROM_SIGNATURES, _fee)));
|
|
emit FeeDistributedFromSignatures(_fee, _txHash);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @dev Internal function for distributing the fee for collecting sufficient amount of affirmations.
|
|
* @param _fee amount of fee to distribute.
|
|
* @param _feeManager address of the fee manager contract.
|
|
* @param _txHash reference transaction hash where the original bridge request happened.
|
|
*/
|
|
function distributeFeeFromAffirmation(uint256 _fee, address _feeManager, bytes32 _txHash) internal {
|
|
if (_fee > 0) {
|
|
require(_feeManager.delegatecall(abi.encodeWithSelector(DISTRIBUTE_FEE_FROM_AFFIRMATION, _fee)));
|
|
emit FeeDistributedFromAffirmation(_fee, _txHash);
|
|
}
|
|
}
|
|
}
|