Update fee contract implementation

This commit is contained in:
Gerardo Nardelli 2019-01-04 16:27:02 -03:00
parent ceb8478528
commit 5991ef31eb
4 changed files with 106 additions and 79 deletions

View File

@ -3,11 +3,12 @@ pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
import "../IFeeManager.sol";
import "../libraries/SafeMath.sol";
import "../IBridgeValidators.sol";
contract BaseFeeManager is EternalStorage {
using SafeMath for uint256;
event FeeUpdated(uint256 fee, uint256 fee);
event FeeUpdated(uint256 fee);
function calculateFee(uint256 _value, bool _recover) external view returns(uint256) {
uint256 fee = getFee();
@ -15,22 +16,50 @@ contract BaseFeeManager is EternalStorage {
if (!_recover) {
return _value.mul(fee).div(eth);
}
return _value.mul(fee).div(eth.sub(fee)); // value * fee / (1 ether - fee)
}
function distributeFeeFromSignatures(uint256 _fee) external {
}
function distributeFeeFromAffirmation(uint256 _fee) external {
return _value.mul(fee).div(eth.sub(fee));
}
function setFee(uint256 _fee) external {
uint256 fee = _fee.mul(1 ether);
uintStorage[keccak256(abi.encodePacked("fee"))] = fee;
emit FeeUpdated(_fee, fee);
uintStorage[keccak256(abi.encodePacked("fee"))] = _fee;
emit FeeUpdated(_fee);
}
function getFee() public view returns(uint256) {
return uintStorage[keccak256(abi.encodePacked("fee"))];
}
function distributeFeeFromAffirmation(uint256 _fee) external {
distributeFeeProportionally(_fee, true);
}
function distributeFeeFromSignatures(uint256 _fee) external {
distributeFeeProportionally(_fee, false);
}
function distributeFeeProportionally(uint256 _fee, bool _isAffirmation) internal {
IBridgeValidators validators = validatorContract();
address [] memory validatorList = validators.validatorList();
uint256 feePerValidator = _fee.div(validatorList.length);
for (uint256 i = 0; i < validatorList.length; i++) {
address rewardAddress = validators.getValidatorRewardAddress(validatorList[i]);
onFeeDistribution(rewardAddress, feePerValidator, _isAffirmation);
}
}
function onFeeDistribution(address _rewardAddress, uint256 _fee, bool _isAffirmation) internal {
if (_isAffirmation) {
onAffirmationFeeDistribution(_rewardAddress, _fee);
} else {
onSignatureFeeDistribution(_rewardAddress, _fee);
}
}
function onAffirmationFeeDistribution(address _rewardAddress, uint256 _fee) internal;
function onSignatureFeeDistribution(address _rewardAddress, uint256 _fee) internal;
function validatorContract() public view returns(IBridgeValidators) {
return IBridgeValidators(addressStorage[keccak256(abi.encodePacked("validatorContract"))]);
}
}

View File

@ -72,19 +72,23 @@ contract BasicHomeBridge is EternalStorage, Validatable {
setNumMessagesSigned(hashMsg, markAsProcessed(signed));
emit CollectedSignatures(msg.sender, hashMsg, reqSigs);
IFeeManager feeManager = feeManagerContract();
address feeManager = feeManagerContract();
if (feeManager != address(0)) {
address receipt;
uint256 amount;
bytes32 txHash;
address contractAddress;
(recipient, amount, txHash, contractAddress) = Message.parseMessage(message);
uint256 fee = feeManager.delegatecall(abi.encodeWithSignatures("calculateFee(uint256,bool)", amount, true));
feeManager.delegatecall(abi.encodeWithSignature("distributeFeeFromSignatures(uint256)", fee));
handleSignatureFeeDistribution(feeManager, message);
}
}
}
function handleSignatureFeeDistribution(address feeManager, bytes message) internal {
address recipient;
uint256 amount;
bytes32 txHash;
address contractAddress;
(recipient, amount, txHash, contractAddress) = Message.parseMessage(message);
uint256 fee = calculateFee(amount, true, feeManager);
feeManager.delegatecall(abi.encodeWithSignature("distributeFeeFromSignatures(uint256)", fee));
}
function setMessagesSigned(bytes32 _hash, bool _status) internal {
boolStorage[keccak256(abi.encodePacked("messagesSigned", _hash))] = _status;
}
@ -156,4 +160,40 @@ contract BasicHomeBridge is EternalStorage, Validatable {
function requiredMessageLength() public pure returns(uint256) {
return Message.requiredMessageLength();
}
function feeManagerContract() public view returns(address) {
return addressStorage[keccak256(abi.encodePacked("feeManagerContract"))];
}
function setFeeManagerContract(address _feeManager) public onlyOwner {
require(_feeManager == address(0) || isContract(_feeManager));
addressStorage[keccak256(abi.encodePacked("feeManagerContract"))] = _feeManager;
}
function isContract(address _addr) internal view returns (bool)
{
uint length;
assembly { length := extcodesize(_addr) }
return length > 0;
}
function calculateFee(uint256 _value, bool _recover, address _impl) internal view returns(uint256) {
uint256 fee;
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize)
let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
mstore(0x40, add(ptr, returndatasize))
returndatacopy(ptr, 0, returndatasize)
switch result
case 0 { revert(ptr, returndatasize) }
default { fee := ptr }
}
return fee;
}
}

View File

@ -2,70 +2,20 @@ pragma solidity 0.4.24;
import "../BaseFeeManager.sol";
import "../Validatable.sol";
import "../../libraries/SafeMath.sol";
import "../../IBridgeValidators.sol";
import "../../IBlockReward.sol";
contract FeeManagerErcToNative is BaseFeeManager, Validatable {
using SafeMath for uint256;
function distributeFeeFromAffirmation(uint256 _fee) external {
// TODO: decide whether distribute by stake or proportionally
distributeFeeFromAffirmationProportionally(_fee);
function blockRewardContract() internal view returns(IBlockReward) {
return IBlockReward(addressStorage[keccak256(abi.encodePacked("blockRewardContract"))]);
}
function distributeFeeFromSignatures(uint256 _fee) external {
// TODO: decide whether distribute by stake or proportionally
distributeFeeFromSignatureProportionally(_fee);
}
//
// Distribute Proportionally
//
function distributeFeeFromAffirmationProportionally(uint _fee) private {
uint256 feePerValidator = proportionalFee();
address nextValidator = validators.getNextValidator(validators.F_ADDR());
while (nextValidator != validators.F_ADDR()) {
address rewardAddress = validators.getValidatorRewardAddress(nextValidator);
require(rewardAddress != address(0));
blockReward.addExtraReceiver(feePerValidator, rewardAddress);
nextValidator = validators.getNextValidator(nextValidator);
}
}
function distributeFeeFromSignatureProportionally(uint _fee) private {
uint256 feePerValidator = proportionalFee();
address nextValidator = validators.getNextValidator(validators.F_ADDR());
while (nextValidator != validators.F_ADDR()) {
address rewardAddress = validators.getValidatorRewardAddress(nextValidator);
require(rewardAddress != address(0));
rewardAddress.send(feePerValidator);
nextValidator = validators.getNextValidator(nextValidator);
}
}
function proportionalFee() private returns(uint256) {
IBridgeValidators validators = validatorContract();
function onAffirmationFeeDistribution(address _rewardAddress, uint256 _fee) internal {
IBlockReward blockReward = blockRewardContract();
uint256 validatorsCount = validators.validatorCount();
uint256 feePerValidator = _fee.div(validatorsCount);
return feePerValidator;
blockReward.addExtraReceiver(_fee, _rewardAddress);
}
//
// Distribute By Stake
//
function distributeFeeFromSignatureByStake(uint _fee) private {
// TODO: implement fee distribution from signature by stake
}
function distributeFeeFromAffirmationByStake(uint _fee) private {
// TODO: implement fee distribution from affirmation by stake
}
function stakeBasedFee(address _validator) private returns(uint256) {
// TODO: calculate fee for _validator based on its stake
function onSignatureFeeDistribution(address _rewardAddress, uint256 _fee) internal {
_rewardAddress.send(_fee);
}
}

View File

@ -21,9 +21,9 @@ contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge {
require(msg.value <= totalMinted.sub(totalBurntCoins()));
setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(msg.value));
uint256 valueToTransfer = msg.value;
IFeeManager feeManager = feeManagerContract();
address feeManager = feeManagerContract();
if (feeManager != address(0)) {
uint256 fee = feeManager.delegateCall(abi.encodeWithSignature("calculateFee(uint256,bool)", valueToTransfer, false));
uint256 fee = calculateFee(valueToTransfer, false, feeManager);
valueToTransfer = valueToTransfer - fee;
}
setTotalBurntCoins(totalBurntCoins().add(valueToTransfer));
@ -82,9 +82,9 @@ contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge {
require(blockReward != address(0));
uint256 valueToMint = msg.value;
IFeeManager feeManager = feeManagerContract();
address feeManager = feeManagerContract();
if (feeManager != address(0)) {
uint256 fee = feeManager.delegatecall(abi.encodeWithSignature("calculateFee(uint256,bool)", valueToMint, false));
uint256 fee = calculateFee(valueToMint, false, feeManager);
feeManager.delegatecall(abi.encodeWithSignature("distributeFeeFromAffirmation(uint256)", fee));
valueToMint = valueToMint - fee;
}
@ -100,4 +100,12 @@ contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge {
function setTotalBurntCoins(uint256 _amount) internal {
uintStorage[keccak256(abi.encodePacked("totalBurntCoins"))] = _amount;
}
function setFee(uint256 _fee) external onlyOwner {
require(feeManagerContract().delegatecall(abi.encodeWithSignature("setFee(uint256)", _fee)));
}
function getFee() public view returns(uint256) {
return uintStorage[keccak256(abi.encodePacked("fee"))];
}
}