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

Maker fee #64

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 20 additions & 14 deletions contracts/carbon/CarbonController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ contract CarbonController is
uint256[MAX_GAP] private __gap;

error IdenticalAddresses();
error UnnecessaryNativeTokenReceived();
error InsufficientNativeTokenReceived();
error DeadlineExpired();

/**
Expand Down Expand Up @@ -122,6 +120,13 @@ contract CarbonController is
return _currentTradingFeePPM();
}

/**
* @inheritdoc ICarbonController
*/
function makerFee() external view returns (uint256) {
return _currentMakerFee();
}

/**
* @dev sets the trading fee (in units of PPM)
*
Expand All @@ -133,6 +138,17 @@ contract CarbonController is
_setTradingFeePPM(newTradingFeePPM);
}

/**
* @dev sets the maker fee (in native token units)
*
* requirements:
*
* - the caller must be the admin of the contract
*/
function setMakerFee(uint256 newMakerFee) external onlyAdmin validMakerFee(newMakerFee) {
_setMakerFee(newMakerFee);
}

/**
* @inheritdoc ICarbonController
*/
Expand Down Expand Up @@ -171,11 +187,6 @@ contract CarbonController is
) external payable nonReentrant whenNotPaused onlyProxyDelegate returns (uint256) {
_validateInputTokens(token0, token1);

// don't allow unnecessary eth
if (!token0.isNative() && !token1.isNative() && msg.value > 0) {
revert UnnecessaryNativeTokenReceived();
}

// revert if any of the orders is invalid
_validateOrders(orders);

Expand Down Expand Up @@ -206,11 +217,6 @@ contract CarbonController is
revert AccessDenied();
}

// don't allow unnecessary eth
if (!__pair.tokens[0].isNative() && !__pair.tokens[1].isNative() && msg.value > 0) {
revert UnnecessaryNativeTokenReceived();
}

// revert if any of the orders is invalid
_validateOrders(newOrders);

Expand All @@ -223,7 +229,7 @@ contract CarbonController is
/**
* @inheritdoc ICarbonController
*/
function deleteStrategy(uint256 strategyId) external nonReentrant whenNotPaused onlyProxyDelegate {
function deleteStrategy(uint256 strategyId) external payable nonReentrant whenNotPaused onlyProxyDelegate {
// find strategy, reverts if none
Pair memory __pair = _pairById(_pairIdByStrategyId(strategyId));
Strategy memory __strategy = _strategy(strategyId, _voucher, __pair);
Expand All @@ -234,7 +240,7 @@ contract CarbonController is
}

// delete strategy
_deleteStrategy(__strategy, _voucher, __pair);
_deleteStrategy(__strategy, _voucher, __pair, msg.value);
}

/**
Expand Down
68 changes: 65 additions & 3 deletions contracts/carbon/Strategies.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/m
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { MathEx } from "../utility/MathEx.sol";
import { InvalidIndices } from "../utility/Utils.sol";
import { Token } from "../token/Token.sol";
import { Token, NATIVE_TOKEN } from "../token/Token.sol";
import { Pair } from "./Pairs.sol";
import { IVoucher } from "../voucher/interfaces/IVoucher.sol";
import { PPM_RESOLUTION } from "../utility/Constants.sol";
Expand Down Expand Up @@ -137,6 +137,8 @@ abstract contract Strategies is Initializable {
error InvalidRate();
error InvalidTradeActionStrategyId();
error InvalidTradeActionAmount();
error UnnecessaryNativeTokenReceived();
error InsufficientNativeTokenReceived();
error StrategyDoesNotExist();
error OutDated();

Expand All @@ -156,6 +158,8 @@ abstract contract Strategies is Initializable {

uint256 private constant ONE = 1 << 48;

uint256 private constant DEFAULT_MAKER_FEE = 0.0005 ether;

uint32 private constant DEFAULT_TRADING_FEE_PPM = 2000; // 0.2%

// total number of strategies
Expand All @@ -164,6 +168,9 @@ abstract contract Strategies is Initializable {
// the global trading fee (in units of PPM)
uint32 private _tradingFeePPM;

// the global maker fee (for strategy owners, in native token units)
uint256 private _makerFee;

// mapping between a strategy to its packed orders
mapping(uint256 => uint256[3]) private _packedOrdersByStrategyId;

Expand All @@ -174,13 +181,18 @@ abstract contract Strategies is Initializable {
mapping(Token => uint256) internal _accumulatedFees;

// upgrade forward-compatibility storage gap
uint256[MAX_GAP - 4] private __gap;
uint256[MAX_GAP - 5] private __gap;

/**
* @dev triggered when the network fee is updated
*/
event TradingFeePPMUpdated(uint32 prevFeePPM, uint32 newFeePPM);

/**
* @dev triggered when the maker fee is updated
*/
event MakerFeeUpdated(uint256 prevFee, uint256 newFee);

/**
* @dev triggered when a strategy is created
*/
Expand Down Expand Up @@ -248,6 +260,7 @@ abstract contract Strategies is Initializable {
*/
function __Strategies_init_unchained() internal onlyInitializing {
_setTradingFeePPM(DEFAULT_TRADING_FEE_PPM);
_setMakerFee(DEFAULT_MAKER_FEE);
}

// solhint-enable func-name-mixedcase
Expand All @@ -263,6 +276,9 @@ abstract contract Strategies is Initializable {
address owner,
uint256 value
) internal returns (uint256) {
// account for maker fee
bool revertOnExcess = !tokens[0].isNative() && !tokens[1].isNative();
value = _deductMakerFee(revertOnExcess, value);
// transfer funds
_validateDepositAndRefundExcessNativeToken(tokens[0], owner, orders[0].y, value);
_validateDepositAndRefundExcessNativeToken(tokens[1], owner, orders[1].y, value);
Expand Down Expand Up @@ -304,6 +320,9 @@ abstract contract Strategies is Initializable {
address owner,
uint256 value
) internal {
// account for maker fee
bool revertOnExcess = !pair.tokens[0].isNative() && !pair.tokens[1].isNative();
value = _deductMakerFee(revertOnExcess, value);
barakman marked this conversation as resolved.
Show resolved Hide resolved
// prepare storage variable
uint256[3] storage packedOrders = _packedOrdersByStrategyId[strategyId];
uint256[3] memory packedOrdersMemory = _packedOrdersByStrategyId[strategyId];
Expand Down Expand Up @@ -357,7 +376,9 @@ abstract contract Strategies is Initializable {
/**
* @dev deletes a strategy
*/
function _deleteStrategy(Strategy memory strategy, IVoucher voucher, Pair memory pair) internal {
function _deleteStrategy(Strategy memory strategy, IVoucher voucher, Pair memory pair, uint256 value) internal {
// account for maker fee
_deductMakerFee(true, value);
// burn the voucher nft token
voucher.burn(strategy.id);

Expand Down Expand Up @@ -637,6 +658,26 @@ abstract contract Strategies is Initializable {
}
}

/**
* @dev checks if maker fee has been sent with the transaction and returns updated tx value
*/
function _deductMakerFee(bool revertOnExcess, uint256 txValue) private returns (uint256) {
uint256 fee = _makerFee;
// revert if not enough native token is sent
if (txValue < fee) {
revert InsufficientNativeTokenReceived();
}
// revert if excess native token is sent
if (revertOnExcess && txValue > fee) {
revert UnnecessaryNativeTokenReceived();
}
barakman marked this conversation as resolved.
Show resolved Hide resolved
// update accumulated fees
if (fee != 0) {
_accumulatedFees[NATIVE_TOKEN] += fee;
}
return txValue - fee;
}

function _validateTradeParams(uint128 pairId, uint256 strategyId, uint128 tradeAmount) private pure {
// make sure the strategy id matches the pair id
if (_pairIdByStrategyId(strategyId) != pairId) {
Expand All @@ -663,13 +704,34 @@ abstract contract Strategies is Initializable {
emit TradingFeePPMUpdated({ prevFeePPM: prevTradingFeePPM, newFeePPM: newTradingFeePPM });
}

/**
* @dev sets the maker fee (in native token units)
*/
function _setMakerFee(uint256 newMakerFee) internal {
uint256 prevMakerFee = _makerFee;
if (prevMakerFee == newMakerFee) {
return;
}

_makerFee = newMakerFee;

emit MakerFeeUpdated(prevMakerFee, newMakerFee);
}

/**
* returns the current trading fee
*/
function _currentTradingFeePPM() internal view returns (uint32) {
return _tradingFeePPM;
}

/**
* returns the current maker fee
*/
function _currentMakerFee() internal view returns (uint256) {
return _makerFee;
}

/**
* returns the current amount of accumulated fees for a specific token
*/
Expand Down
7 changes: 6 additions & 1 deletion contracts/carbon/interfaces/ICarbonController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ interface ICarbonController is IUpgradeable {
*/
function tradingFeePPM() external view returns (uint32);

/**
* @dev returns the maker fee (in native token units)
*/
function makerFee() external view returns (uint256);

/**
* @dev creates a new pair of provided token0 and token1
*/
Expand Down Expand Up @@ -81,7 +86,7 @@ interface ICarbonController is IUpgradeable {
*
* - the caller must be the owner of the NFT voucher
*/
function deleteStrategy(uint256 strategyId) external;
function deleteStrategy(uint256 strategyId) external payable;

/**
* @dev returns a strategy matching the provided id,
Expand Down
14 changes: 14 additions & 0 deletions contracts/utility/Utils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,18 @@ abstract contract Utils {
revert InvalidFee();
}
}

// ensures that the maker fee is valid
modifier validMakerFee(uint256 fee) {
_validMakerFee(fee);

_;
}

// error message binary size optimization
function _validMakerFee(uint256 fee) internal pure {
if (fee > 1 ether) {
revert InvalidFee();
}
}
}
Loading