Skip to content
2 changes: 1 addition & 1 deletion contracts/events/ProtocolSettingsEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ contract ProtocolSettingsEvents is ModulesCommonEvents {
uint256 lendingAmount,
uint256 tradingAmount,
uint256 borrowingAmount,
uint256 wRBTCConverted
uint256 wrappedNativeTokenConverted
);

event WithdrawLendingFees(
Expand Down
428 changes: 227 additions & 201 deletions contracts/governance/FeeSharingCollector/FeeSharingCollector.sol

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import "../../interfaces/IERC20.sol";
import "../IFeeSharingCollector.sol";
import "../Staking/interfaces/IStaking.sol";
import "../../mixins/EnumerableAddressSet.sol";
import "../../interfaces/IWrbtcERC20.sol";
import "../../interfaces/IWrappedNativeTokenERC20.sol";

/**
* @title FeeSharingCollectorStorage contact
Expand All @@ -16,6 +16,7 @@ import "../../interfaces/IWrbtcERC20.sol";
contract FeeSharingCollectorStorage is Ownable {
using EnumerableAddressSet for EnumerableAddressSet.AddressSet;
uint256 constant FEE_WITHDRAWAL_INTERVAL = 172800;
uint32 constant MAX_CHECKPOINTS = 100;

IProtocol public protocol;
IStaking public staking;
Expand Down Expand Up @@ -79,12 +80,17 @@ contract FeeSharingCollectorStorage is Ownable {
/**
* @dev Wrapped native token address
*/
address public wrbtcTokenAddress;
address public wrappedNativeTokenAddress;

/**
* @dev Wrapped native token loan token address
*/
address public loanTokenWrbtcAddress;
address public loanWrappedNativeTokenAddress;

/**
* @dev sovrynDex
*/
address public sovrynDexAddress;

/**
* @dev Prevents a contract from calling itself, directly or indirectly.
Expand All @@ -100,6 +106,16 @@ contract FeeSharingCollectorStorage is Ownable {
_;
reentrancyLock = REENTRANCY_GUARD_FREE;
}

/* Modifier */
modifier oneTimeExecution(bytes4 _funcSig) {
require(
!isFunctionExecuted[_funcSig],
"FeeSharingCollector: function can only be called once"
);
_;
isFunctionExecuted[_funcSig] = true;
}
}

/* Interfaces */
Expand All @@ -110,16 +126,16 @@ interface IProtocol {
* @param tokens The array address of the token instance.
* @param receiver The address of the withdrawal recipient.
*
* @return The withdrawn total amount in wRBTC
* @return The withdrawn total amount in wrappedNativeToken
* */
function withdrawFees(
address[] calldata tokens,
address receiver
) external returns (uint256 totalWRBTCWithdrawn);
) external returns (uint256 totalWrappedNativeTokenWithdrawn);

function underlyingToLoanPool(address token) external view returns (address);

function wrbtcToken() external view returns (IWrbtcERC20);
function wrappedNativeToken() external view returns (IWrappedNativeTokenERC20);

function getSovTokenAddress() external view returns (address);
}
19 changes: 19 additions & 0 deletions contracts/governance/IFeeSharingCollectorMultipleToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
pragma solidity ^0.5.17;

/**
* @title Interface for contract governance/FeeSharingCollector/FeeSharingCollector.sol
* @dev Interfaces are used to cast a contract address into a callable instance.
* */
interface IFeeSharingCollectorMultipleToken {
function withdrawFees(address[] calldata _token) external;

function transferTokens(address _token, uint96 _amount) external;

function withdraw(address _token, uint32 _maxCheckpoint, address _receiver) external;

function withdrawTokens(
address[] calldata _tokens,
uint32[] calldata _maxCheckpoints,
address _receiver
) external;
}
5 changes: 5 additions & 0 deletions contracts/interfaces/ISovrynDex.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma solidity 0.5.17;

interface ISovrynDex {
function userCmd(uint16 callpath, bytes calldata cmd) external payable returns (bytes memory);
}
12 changes: 12 additions & 0 deletions contracts/interfaces/IWrappedNativeToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0.
*/

pragma solidity >=0.5.0 <0.6.0;

interface IWrappedNativeToken {
function deposit() external payable;

function withdraw(uint256 wad) external;
}
11 changes: 11 additions & 0 deletions contracts/interfaces/IWrappedNativeTokenERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0.
*/

pragma solidity >=0.5.0 <0.6.0;

import "./IWrappedNativeToken.sol";
import "./IERC20.sol";

contract IWrappedNativeTokenERC20 is IWrappedNativeToken, IERC20 {}
4 changes: 2 additions & 2 deletions contracts/mockup/FeeSharingCollectorMockup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ contract FeeSharingCollectorMockup is FeeSharingCollector {
return _getEndOfRange(0, _token, 0);
}

function getRBTCBalance(
function getNativeTokenBalance(
address _token,
address _user,
uint32 _maxCheckpoints
) public view returns (uint256 _tokenAmount, uint256 _endToken) {
return _getRBTCBalance(_token, _user, _maxCheckpoints);
return _getNativeTokenBalance(_token, _user, _maxCheckpoints);
}

function testWithdrawReentrancy(
Expand Down
42 changes: 42 additions & 0 deletions contracts/mockup/FeeSharingCollectorMultipleTokenMockup.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
pragma solidity ^0.5.17;

import "../governance/FeeSharingCollector/FeeSharingCollectorMultipleToken.sol";

contract FeeSharingCollectorMultipleTokenMockup is FeeSharingCollectorMultipleToken {
struct TestData {
address loanPoolToken;
uint32 maxCheckpoints;
address receiver;
}

TestData public testData;

constructor(IProtocol _protocol, IStaking _staking) public {
protocol = _protocol;
staking = _staking;
}

function withdraw(address _token, uint32 _maxCheckpoint, address _receiver) public {
testData = TestData(_token, _maxCheckpoint, _receiver);
}

function trueWithdraw(address _token, uint32 _maxCheckpoint, address _receiver) public {
super.withdraw(_token, _maxCheckpoint, _receiver);
}

function trueWithdrawTokens(
address[] memory _tokens,
uint32[] memory _maxCheckpoints,
address _receiver
) public {
super.withdrawTokens(_tokens, _maxCheckpoints, _receiver);
}

function addCheckPoint(address loanPoolToken, uint256 poolTokenAmount) public {
uint96 amount96 = safe96(
poolTokenAmount,
"FeeSharingProxy::withdrawFees: pool token amount exceeds 96 bits"
);
_addCheckpoint(loanPoolToken, amount96);
}
}
39 changes: 39 additions & 0 deletions contracts/mockup/MockSovrynDex.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
pragma solidity 0.5.17;

import "../interfaces/IERC20.sol";

contract MockSovrynDex {
mapping(address => uint256) public tokenFees;
uint16 public constant SOVRYN_DEX_COLD_PATH_PROXY_IDX = 3;
uint8 public constant SOVRYN_DEX_CMD_COLLECT_TREASURY_CODE = 40;
IERC20 wrbtcToken;
address treasury;

constructor() public {}

function setTreasury(address _treasury) public {
treasury = _treasury;
}

function setWrbtcToken(IERC20 _wrbtcToken) public {
wrbtcToken = _wrbtcToken;
}

function userCmd(uint16 callpath, bytes calldata cmd) external payable returns (bytes memory) {
require(msg.sender == treasury, "Only Treasury");
(uint8 cmdCode, address token) = abi.decode(cmd, (uint8, address));
if (
callpath == SOVRYN_DEX_COLD_PATH_PROXY_IDX &&
cmdCode == SOVRYN_DEX_CMD_COLLECT_TREASURY_CODE
) {
wrbtcToken.transfer(msg.sender, tokenFees[token]);
return abi.encode(tokenFees[token]);
} else {
return "0x";
}
}

function setTokenDexFee(address token, uint256 fee) external {
tokenFees[token] = fee;
}
}
37 changes: 37 additions & 0 deletions contracts/mockup/MockSovrynDexMultipleToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
pragma solidity 0.5.17;

import "../interfaces/IERC20.sol";
import "../governance/IFeeSharingCollectorMultipleToken.sol";

contract MockSovrynDexMultipleToken {
mapping(address => uint96) public tokenFees;
uint16 public constant SOVRYN_DEX_COLD_PATH_PROXY_IDX = 3;
uint8 public constant SOVRYN_DEX_CMD_COLLECT_TREASURY_CODE = 40;
IERC20 wrbtcToken;
address treasury;

constructor() public {}

function setTreasury(address _treasury) public {
treasury = _treasury;
}

function setWrbtcToken(IERC20 _wrbtcToken) public {
wrbtcToken = _wrbtcToken;
}

function userCmd(uint16 callpath, bytes calldata cmd) external payable {
require(msg.sender == treasury, "Only Treasury");
(uint8 cmdCode, address token) = abi.decode(cmd, (uint8, address));
if (
callpath == SOVRYN_DEX_COLD_PATH_PROXY_IDX &&
cmdCode == SOVRYN_DEX_CMD_COLLECT_TREASURY_CODE
) {
IFeeSharingCollectorMultipleToken(treasury).transferTokens(token, tokenFees[token]);
}
}

function setTokenDexFee(address token, uint96 fee) external {
tokenFees[token] = fee;
}
}
Loading