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

Add fee manager for Native-to-ERC that collects fees on home network #155

Merged
26 changes: 24 additions & 2 deletions REWARD_MANAGEMENT.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# Reward Management

## NATIVE-TO-ERC

Configuration:
```
HOME_REWARDABLE=ONE_DIRECTION
FOREIGN_REWARDABLE=ONE_DIRECTION
```
### Home to Foreign transfer
Fees are calculated and distributed on Foreign network. Validators will receive ERC20 tokens.
![native-erc-hometoforeign](https://user-images.githubusercontent.com/4614574/51607402-4bda6180-1ef3-11e9-91e3-50fe5d35d296.png)
Expand All @@ -10,8 +14,26 @@ Fees are calculated and distributed on Foreign network. Validators will receive
Fees are calculated and distributed on Home network. Validators will receive native coins.
![native-erc-foreigntohome](https://user-images.githubusercontent.com/4614574/51607428-5d236e00-1ef3-11e9-8083-3669899c7252.png)

## ERC-TO-NATIVE
## NATIVE-TO-ERC - Fees collected on Home network only
Configuration:
```
HOME_REWARDABLE=BOTH_DIRECTIONS
FOREIGN_REWARDABLE=false
```
### Home to Foreign transfer
Fees are calculated and distributed on Home network. Validators will receive native coins.
![native-erc-homefee-hometoforeign](https://user-images.githubusercontent.com/4614574/53118155-43456d00-352b-11e9-80db-53e31494e09b.png)

### Foreign to Home transfer
Fees are calculated and distributed on Home network. Validators will receive native coins.
![native-erc-homefee-foreigntohome](https://user-images.githubusercontent.com/4614574/53118176-4b9da800-352b-11e9-8118-123f30e37d61.png)

## ERC-TO-NATIVE
Configuration:
```
HOME_REWARDABLE=BOTH_DIRECTIONS
FOREIGN_REWARDABLE=false
```
### Foreign to Home transfer
Fees are calculated and distributed on Home network. Validators will receive native coins.
![erc-native-foreigntohome](https://user-images.githubusercontent.com/4614574/51607498-9065fd00-1ef3-11e9-8212-fc1ba16ae91a.png)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
pragma solidity 0.4.24;

import "../Sacrifice.sol";
import "../ValidatorsFeeManager.sol";


contract FeeManagerNativeToErcBothDirections is ValidatorsFeeManager {

function getFeeManagerMode() public pure returns(bytes4) {
return bytes4(keccak256(abi.encodePacked("manages-both-directions")));
}

function onAffirmationFeeDistribution(address _rewardAddress, uint256 _fee) internal {
_sendReward(_rewardAddress, _fee);
}

function onSignatureFeeDistribution(address _rewardAddress, uint256 _fee) internal {
_sendReward(_rewardAddress, _fee);
}

function _sendReward(address _rewardAddress, uint256 _fee) internal {
if (!_rewardAddress.send(_fee)) {
(new Sacrifice).value(_fee)(_rewardAddress);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,10 @@ contract ForeignBridgeNativeToErc is ERC677Receiver, BasicBridge, BasicForeignBr
address feeManager = feeManagerContract();
if (feeManager != address(0)) {
uint256 fee = calculateFee(valueToMint, false, feeManager, HOME_FEE);
distributeFeeFromSignatures(fee, feeManager, _txHash);
valueToMint = valueToMint.sub(fee);
if (fee != 0) {
distributeFeeFromSignatures(fee, feeManager, _txHash);
valueToMint = valueToMint.sub(fee);
}
}
return erc677token().mint(_recipient, valueToMint);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ contract HomeBridgeNativeToErc is EternalStorage, BasicBridge, BasicHomeBridge,
require(msg.data.length == 0);
require(withinLimit(msg.value));
setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(msg.value));
emit UserRequestForSignature(msg.sender, msg.value);
uint256 valueToTransfer = msg.value;
address feeManager = feeManagerContract();
if (feeManager != address(0)) {
uint256 fee = calculateFee(valueToTransfer, false, feeManager, HOME_FEE);
valueToTransfer = valueToTransfer.sub(fee);
}
emit UserRequestForSignature(msg.sender, valueToTransfer);
}

function initialize (
Expand Down Expand Up @@ -56,6 +62,7 @@ contract HomeBridgeNativeToErc is EternalStorage, BasicBridge, BasicHomeBridge,
uint256 _foreignMaxPerTx,
address _owner,
address _feeManager,
uint256 _homeFee,
uint256 _foreignFee
) public returns(bool)
{
Expand All @@ -72,6 +79,7 @@ contract HomeBridgeNativeToErc is EternalStorage, BasicBridge, BasicHomeBridge,
);
require(isContract(_feeManager));
addressStorage[keccak256(abi.encodePacked("feeManagerContract"))] = _feeManager;
_setFee(_feeManager, _homeFee, HOME_FEE);
_setFee(_feeManager, _foreignFee, FOREIGN_FEE);
setInitialize(true);
return isInitialized();
Expand Down Expand Up @@ -112,6 +120,21 @@ contract HomeBridgeNativeToErc is EternalStorage, BasicBridge, BasicHomeBridge,
setOwner(_owner);
}

function onSignaturesCollected(bytes _message) internal {
address feeManager = feeManagerContract();
if (feeManager != address(0)) {
address recipient;
uint256 amount;
bytes32 txHash;
address contractAddress;
(recipient, amount, txHash, contractAddress) = Message.parseMessage(_message);
uint256 fee = calculateFee(amount, true, feeManager, HOME_FEE);
if (fee != 0) {
distributeFeeFromSignatures(fee, feeManager, txHash);
}
}
}

function onExecuteAffirmation(address _recipient, uint256 _value, bytes32 txHash) internal returns(bool) {
setTotalExecutedPerDay(getCurrentDay(), totalExecutedPerDay(getCurrentDay()).add(_value));
uint256 valueToTransfer = _value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@ contract RewardableHomeBridgeNativeToErc is RewardableBridge {
_setFee(feeManagerContract(), _fee, FOREIGN_FEE);
}

function setHomeFee(uint256 _fee) external onlyOwner {
_setFee(feeManagerContract(), _fee, HOME_FEE);
}

function getForeignFee() public view returns(uint256) {
return _getFee(FOREIGN_FEE);
}

function getHomeFee() public view returns(uint256) {
return _getFee(HOME_FEE);
}
}
5 changes: 2 additions & 3 deletions deploy/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,9 @@ REQUIRED_NUMBER_OF_VALIDATORS=1
#If several validators are used, list them separated by space without quotes
#E.g. VALIDATORS=0x 0x 0x
VALIDATORS=0x
#for erc_to_native mode
#Set to true if fee will be charged on home side
#Set to ONE_DIRECTION or BOTH_DIRECTIONS if fee will be charged on home side, set to false otherwise
HOME_REWARDABLE=false
#Set to true if fee will be charged on foreign side
#Set to ONE_DIRECTION or BOTH_DIRECTIONS if fee will be charged on foreign side, set to false otherwise
FOREIGN_REWARDABLE=false
#If HOME_REWARDABLE or FOREIGN_REWARDABLE set to true, list validators accounts were rewards should be transferred separated by space without quotes
#E.g. VALIDATORS_REWARD_ACCOUNTS=0x 0x 0x
Expand Down
24 changes: 14 additions & 10 deletions deploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,22 @@ REQUIRED_NUMBER_OF_VALIDATORS=1
# correctly to the Foreign network.
VALIDATORS=0x 0x 0x

# The flag defining whether to use RewardableValidators contract and set a fee manager contract on Home network
# Variable to define whether to use RewardableValidators contract and set a fee manager contract on Home network
# On this bridge mode ONE_DIRECTION and BOTH_DIRECTIONS are supported on Home network
HOME_REWARDABLE=false
# The flag defining whether to use RewardableValidators contract and set a fee manager contract on Foreign network
# Variable to define whether to use RewardableValidators contract and set a fee manager contract on Foreign network
# On this bridge mode ONE_DIRECTION is supported on Foreign network
FOREIGN_REWARDABLE=false
# List validators accounts were rewards should be transferred separated by space without quotes
# Makes sense only when HOME_REWARDABLE=true or FOREIGN_REWARDABLE=true
# Makes sense only when HOME_REWARDABLE!=false or FOREIGN_REWARDABLE!=false
VALIDATORS_REWARD_ACCOUNTS=0x 0x 0x

# Fee to be taken for every transaction directed from the Home network to the Foreign network
# Makes sense only when FOREIGN_REWARDABLE=true
# Makes sense only when FOREIGN_REWARDABLE=ONE_DIRECTION or HOME_REWARDABLE=BOTH_DIRECTIONS
# e.g. 0.1% fee
HOME_TRANSACTIONS_FEE=0.001
# Fee to be taken for every transaction directed from the Foreign network to the Home network
# Makes sense only when HOME_REWARDABLE=true
# Makes sense only when HOME_REWARDABLE!=false
# e.g. 0.1% fee
FOREIGN_TRANSACTIONS_FEE=0.001

Expand Down Expand Up @@ -357,20 +359,22 @@ REQUIRED_NUMBER_OF_VALIDATORS=1
VALIDATORS=0x 0x 0x


# The flag defining whether to use RewardableValidators contract and set a fee manager contract on Home network
# Variable to define whether to use RewardableValidators contract and set a fee manager contract on Home network
# On this bridge mode only BOTH_DIRECTIONS is supported on Home network
HOME_REWARDABLE=false
# The flag defining whether to use RewardableValidators contract and set a fee manager contract on Foreign network
# Variable to define whether to use RewardableValidators contract and set a fee manager contract on Foreign network
# Collecting fees on Foreign network is not supported on this bridge mode.
FOREIGN_REWARDABLE=false
# List validators accounts were rewards should be transferred separated by space without quotes
# Makes sense only when HOME_REWARDABLE=true or FOREIGN_REWARDABLE=true
# Makes sense only when HOME_REWARDABLE=BOTH_DIRECTIONS
VALIDATORS_REWARD_ACCOUNTS=0x 0x 0x

# Fee to be taken for every transaction directed from the Home network to the Foreign network
# Makes sense only when HOME_REWARDABLE=true
# Makes sense only when HOME_REWARDABLE=BOTH_DIRECTIONS
# e.g. 0.1% fee
HOME_TRANSACTIONS_FEE=0.001
# Fee to be taken for every transaction directed from the Foreign network to the Home network
# Makes sense only when HOME_REWARDABLE=true
# Makes sense only when HOME_REWARDABLE=BOTH_DIRECTIONS
# e.g. 0.1% fee
FOREIGN_TRANSACTIONS_FEE=0.001
```
2 changes: 1 addition & 1 deletion deploy/src/erc_to_native/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const {

const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)

const isRewardableBridge = HOME_REWARDABLE === 'true'
const isRewardableBridge = HOME_REWARDABLE === 'BOTH_DIRECTIONS'

async function deployHome() {
let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
Expand Down
35 changes: 33 additions & 2 deletions deploy/src/loadEnv.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const { ZERO_ADDRESS } = require('./constants')

// Validations and constants
const validBridgeModes = ['NATIVE_TO_ERC', 'ERC_TO_ERC', 'ERC_TO_NATIVE']
const validRewardModes = ['false', 'ONE_DIRECTION', 'BOTH_DIRECTIONS']
const bigNumValidator = envalid.makeValidator(x => toBN(x))
const validateAddress = address => {
if (isAddress(address)) {
Expand Down Expand Up @@ -44,6 +45,18 @@ if (!validBridgeModes.includes(BRIDGE_MODE)) {
throw new Error(`Invalid bridge mode: ${BRIDGE_MODE}`)
}

if (!validRewardModes.includes(HOME_REWARDABLE)) {
throw new Error(
`Invalid HOME_REWARDABLE: ${HOME_REWARDABLE}. Supported values are ${validRewardModes}`
)
}

if (!validRewardModes.includes(FOREIGN_REWARDABLE)) {
throw new Error(
`Invalid FOREIGN_REWARDABLE: ${FOREIGN_REWARDABLE}. Supported values are ${validRewardModes}`
)
}

let validations = {
DEPLOYMENT_ACCOUNT_PRIVATE_KEY: envalid.str(),
DEPLOYMENT_GAS_LIMIT: bigNumValidator(),
Expand Down Expand Up @@ -88,6 +101,18 @@ if (BRIDGE_MODE === 'NATIVE_TO_ERC') {
DPOS_STAKING_ADDRESS: addressValidator()
}
}

if (FOREIGN_REWARDABLE === 'BOTH_DIRECTIONS') {
throw new Error(
`FOREIGN_REWARDABLE: ${FOREIGN_REWARDABLE} is not supported on ${BRIDGE_MODE} bridge mode`
)
}

if (HOME_REWARDABLE === 'BOTH_DIRECTIONS' && FOREIGN_REWARDABLE === 'ONE_DIRECTION') {
throw new Error(
`Combination of HOME_REWARDABLE: ${HOME_REWARDABLE} and FOREIGN_REWARDABLE: ${FOREIGN_REWARDABLE} should be avoided on ${BRIDGE_MODE} bridge mode.`
)
}
}
if (BRIDGE_MODE === 'ERC_TO_ERC') {
validations = {
Expand Down Expand Up @@ -116,14 +141,20 @@ if (BRIDGE_MODE === 'ERC_TO_NATIVE') {
})
}

if (FOREIGN_REWARDABLE === 'true') {
if (HOME_REWARDABLE === 'ONE_DIRECTION') {
throw new Error(
`Only BOTH_DIRECTIONS is supported for collecting fees on Home Network on ${BRIDGE_MODE} bridge mode.`
)
}

if (FOREIGN_REWARDABLE !== 'false') {
throw new Error(
`Collecting fees on Foreign Network on ${BRIDGE_MODE} bridge mode is not supported.`
)
}
}

if (HOME_REWARDABLE === 'true' || FOREIGN_REWARDABLE === 'true') {
if (HOME_REWARDABLE !== 'false' || FOREIGN_REWARDABLE !== 'false') {
validateRewardableAddresses(VALIDATORS, VALIDATORS_REWARD_ACCOUNTS)
validations = {
...validations,
Expand Down
2 changes: 1 addition & 1 deletion deploy/src/native_to_erc/foreign.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const {

const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)

const isRewardableBridge = FOREIGN_REWARDABLE === 'true'
const isRewardableBridge = FOREIGN_REWARDABLE === 'ONE_DIRECTION'

async function deployForeign() {
let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
Expand Down
14 changes: 12 additions & 2 deletions deploy/src/native_to_erc/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const EternalStorageProxy = require('../../../build/contracts/EternalStorageProx
const BridgeValidators = require('../../../build/contracts/BridgeValidators.json')
const RewardableValidators = require('../../../build/contracts/RewardableValidators.json')
const FeeManagerNativeToErc = require('../../../build/contracts/FeeManagerNativeToErc.json')
const FeeManagerNativeToErcBothDirections = require('../../../build/contracts/FeeManagerNativeToErcBothDirections.json')
const HomeBridge = require('../../../build/contracts/HomeBridgeNativeToErc.json')

const VALIDATORS = env.VALIDATORS.split(' ')
Expand All @@ -33,12 +34,14 @@ const {
FOREIGN_DAILY_LIMIT,
FOREIGN_MAX_AMOUNT_PER_TX,
HOME_REWARDABLE,
HOME_TRANSACTIONS_FEE,
FOREIGN_TRANSACTIONS_FEE
} = env

const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)

const isRewardableBridge = HOME_REWARDABLE === 'true'
const isBothDirectionsFeeManager = HOME_REWARDABLE === 'BOTH_DIRECTIONS'
const isRewardableBridge = HOME_REWARDABLE === 'ONE_DIRECTION' || isBothDirectionsFeeManager

async function deployHome() {
let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
Expand Down Expand Up @@ -159,13 +162,18 @@ async function deployHome() {

if (isRewardableBridge) {
console.log('\ndeploying implementation for fee manager')
const feeManager = await deployContract(FeeManagerNativeToErc, [], {
const feeManagerContract = isBothDirectionsFeeManager
? FeeManagerNativeToErcBothDirections
: FeeManagerNativeToErc
const feeManager = await deployContract(feeManagerContract, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce: homeNonce
})
console.log('[Home] feeManager Implementation: ', feeManager.options.address)
homeNonce++

const homeFee = isBothDirectionsFeeManager ? HOME_TRANSACTIONS_FEE.toString() : '0'
const homeFeeInWei = Web3Utils.toWei(homeFee, 'ether')
const foreignFeeInWei = Web3Utils.toWei(FOREIGN_TRANSACTIONS_FEE.toString(), 'ether')

console.log('\ninitializing Home Bridge with fee contract:\n')
Expand All @@ -186,6 +194,7 @@ async function deployHome() {
)} in eth,
HOME_BRIDGE_OWNER: ${HOME_BRIDGE_OWNER},
Fee Manager: ${feeManager.options.address},
Home Fee: ${homeFeeInWei} which is ${homeFee * 100}%
Foreign Fee: ${foreignFeeInWei} which is ${FOREIGN_TRANSACTIONS_FEE * 100}%`)

homeBridgeImplementation.options.address = homeBridgeStorage.options.address
Expand All @@ -201,6 +210,7 @@ async function deployHome() {
FOREIGN_MAX_AMOUNT_PER_TX,
HOME_BRIDGE_OWNER,
feeManager.options.address,
homeFeeInWei,
foreignFeeInWei
)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
Expand Down
Loading