DexManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
library Bytes32Library {
// utility function to convert bytes32 to string
function bytes32ToString(bytes32 _bytes32) internal pure returns (string memory) {
uint8 i = 0;
while(i < 32 && _bytes32[i] != 0) {
i++;
}
bytes memory bytesArray = new bytes(i);
for (i = 0; i < 32 && _bytes32[i] != 0; i++) {
bytesArray[i] = _bytes32[i];
}
return string(bytesArray);
}
}
library StringLibrary {
// utility function to convert string to bytes32
function stringToBytes32(string memory _string) internal pure returns (bytes32 result) {
bytes memory tempEmptyStringTest = bytes(_string);
if (tempEmptyStringTest.length == 0) {
return 0x0;
}
assembly {
result := mload(add(_string, 32))
}
}
}
interface IPortfolio {
function pause() external;
function unpause() external;
function pauseDeposit(bool _paused) external;
function updateTransferFeeRate(uint _rate, IPortfolio.Tx _rateType) external;
function addToken(bytes32 _symbol, IERC20Upgradeable _token) external;
function adjustAvailable(Tx _transaction, address _trader, bytes32 _symbol, uint _amount) external;
function addExecution(ITradePairs.Order memory _maker, address _taker, bytes32 _baseSymbol, bytes32 _quoteSymbol,
uint _baseAmount, uint _quoteAmount, uint _makerfeeCharged,
uint _takerfeeCharged) external;
function addAdmin(address _address) external;
function removeAdmin(address _address) external;
enum Tx {WITHDRAW, DEPOSIT, EXECUTION, INCREASEAVAIL, DECREASEAVAIL}
event PortfolioUpdated(Tx indexed transaction, address indexed wallet, bytes32 indexed symbol,
uint256 quantity, uint256 feeCharged, uint256 total, uint256 available, address refer);
}
interface ITradePairs {
struct Order {
bytes32 id;
uint price;
uint totalAmount;
uint quantity;
uint quantityFilled;
uint totalFee;
address traderaddress;
Side side;
Type1 type1;
Status status;
}
function pause() external;
function unpause() external;
function pauseTradePair(bytes32 _tradePairId, bool _pairPaused) external;
function pauseAddOrder(bytes32 _tradePairId, bool _allowAddOrder) external;
function addTradePair(bytes32 _tradePairId, bytes32 _baseSymbol, uint8 _baseDecimals, uint8 _baseDisplayDecimals,
bytes32 _quoteSymbol, uint8 _quoteDecimals, uint8 _quoteDisplayDecimals,
uint _minTradeAmount, uint _maxTradeAmount) external;
function getTradePairs() external view returns (bytes32[] memory);
function setMinTradeAmount(bytes32 _tradePairId, uint _minTradeAmount) external;
function getMinTradeAmount(bytes32 _tradePairId) external view returns (uint);
function setMaxTradeAmount(bytes32 _tradePairId, uint _maxTradeAmount) external;
function getMaxTradeAmount(bytes32 _tradePairId) external view returns (uint);
function addOrderType(bytes32 _tradePairId, Type1 _type) external;
function removeOrderType(bytes32 _tradePairId, Type1 _type) external;
function setDisplayDecimals(bytes32 _tradePairId, uint8 _displayDecimals, bool _isBase) external;
function getDisplayDecimals(bytes32 _tradePairId, bool _isBase) external view returns (uint8);
function getDecimals(bytes32 _tradePairId, bool _isBase) external view returns (uint8);
function getSymbol(bytes32 _tradePairId, bool _isBase) external view returns (bytes32);
function updateRate(bytes32 _tradePairId, uint _rate, RateType _rateType) external;
function getMakerRate(bytes32 _tradePairId) external view returns (uint);
function getTakerRate(bytes32 _tradePairId) external view returns (uint);
function setAllowedSlippagePercent(bytes32 _tradePairId, uint8 _allowedSlippagePercent) external;
function getAllowedSlippagePercent(bytes32 _tradePairId) external view returns (uint8);
function getNSellBook(bytes32 _tradePairId, uint nPrice, uint nOrder, uint lastPrice, bytes32 lastOrder) external view
returns (uint[] memory, uint[] memory, uint , bytes32);
function getNBuyBook(bytes32 _tradePairId, uint nPrice, uint nOrder, uint lastPrice, bytes32 lastOrder) external view
returns (uint[] memory, uint[] memory, uint , bytes32);
function getOrder(bytes32 _orderUid) external view returns (Order memory);
function addOrder(bytes32 _tradePairId, uint _price, uint _quantity, Side _side, Type1 _type1) external;
function cancelOrder(bytes32 _tradePairId, bytes32 _orderId) external;
function cancelAllOrders(bytes32 _tradePairId, bytes32[] memory _orderIds) external;
enum Side {BUY, SELL}
enum Type1 {MARKET, LIMIT, STOP, STOPLIMIT, LIMITFOK}
enum Status {NEW, REJECTED, PARTIAL, FILLED, CANCELED, EXPIRED, KILLED}
enum RateType {MAKER, TAKER}
enum Type2 {GTC, FOK}
}
contract DexOwner {
using SafeERC20Upgradeable for IERC20Upgradeable;
// account collecting fees
mapping(string=>bool) internal adminSettings;
event ChangedSetAdmin(string setting, bool boolean);
event RescueETH(address rescueAddress, uint256 amount);
event RescueTokens(address token, address rescueAddress, uint256 amount);
function setAdmin(string memory setting, bool boolean) external {
adminSettings[setting] = boolean;
emit ChangedSetAdmin(setting, boolean);
}
function rescueETH(address rescueAddress, uint256 amount) external payable {
payable(rescueAddress).transfer(amount);
emit RescueETH(rescueAddress, amount);
}
function rescueTokens(address token, address rescueAddress, uint256 amount) external payable {
IERC20Upgradeable(token).safeTransfer(
rescueAddress,
amount
);
emit RescueTokens(token, rescueAddress, amount);
}
}
contract DexManager is DexOwner, Initializable, AccessControlEnumerableUpgradeable {
using SafeERC20Upgradeable for IERC20MetadataUpgradeable;
using StringLibrary for string;
using Bytes32Library for bytes32;
// map and array of all trading pairs on DEXPOOLS
ITradePairs private tradePairs;
// portfolio reference
IPortfolio private portfolio;
event PortfolioSet(IPortfolio _oldPortfolio, IPortfolio _newPortfolio);
event TradePairsSet(ITradePairs _oldTradePairs, ITradePairs _newTradePairs);
function initialize() public initializer {
__AccessControl_init();
// intitialize the admins
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender); // set deployment account to have DEFAULT_ADMIN_ROLE
// initialize AVAX/USD price feed with fuji testnet contract,
// heart-beat = 2m, decimals = 8
adminSettings['deposits'] = true;
adminSettings['withdraws'] = true;
adminSettings['orders'] = true;
}
function owner() public view returns(address) {
return getRoleMember(DEFAULT_ADMIN_ROLE, 0);
}
function addAdmin(address _address) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-01");
grantRole(DEFAULT_ADMIN_ROLE, _address);
portfolio.addAdmin(_address);
}
function removeAdmin(address _address) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-02");
require(getRoleMemberCount(DEFAULT_ADMIN_ROLE)>1, "E-ALOA-01");
revokeRole(DEFAULT_ADMIN_ROLE, _address);
portfolio.removeAdmin(_address);
}
function isAdmin(address _address) public view returns(bool) {
return hasRole(DEFAULT_ADMIN_ROLE, _address);
}
// FRONTEND FUNCTION TO GET A LIST OF TRADE PAIRS
function getTradePairs() public view returns(bytes32[] memory) {
return tradePairs.getTradePairs();
}
// DEPLOYMENT ACCOUNT FUNCTION TO UPDATE FEE RATES FOR DEPOSIT AND WITHDRAW
function updateTransferFeeRate(uint _rate, IPortfolio.Tx _rateType) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-03");
portfolio.updateTransferFeeRate(_rate, _rateType);
}
// DEPLOYMENT ACCOUNT FUNCTION TO UPDATE FEE RATE FOR EXECUTIONS
function updateRate(bytes32 _tradePair, uint _rate, ITradePairs.RateType _rateType) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-04");
tradePairs.updateRate(_tradePair, _rate, _rateType);
}
// DEPLOYMENT ACCOUNT FUNCTION TO UPDATE FEE RATE FOR EXECUTIONS
function updateRates(bytes32 _tradePair, uint _makerRate, uint _takerRate) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-20");
tradePairs.updateRate(_tradePair, _makerRate, ITradePairs.RateType.MAKER);
tradePairs.updateRate(_tradePair, _takerRate, ITradePairs.RateType.TAKER);
}
// DEPLOYMENT ACCOUNT FUNCTION TO UPDATE ALL FEE RATES FOR EXECUTIONS
function updateAllRates(uint _makerRate, uint _takerRate) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-21");
bytes32[] memory pairs = getTradePairs();
for (uint i=0; i<pairs.length; i++) {
tradePairs.updateRate(pairs[i], _makerRate, ITradePairs.RateType.MAKER);
tradePairs.updateRate(pairs[i], _takerRate, ITradePairs.RateType.TAKER);
}
}
// DEPLOYMENT ACCOUNT FUNCTION TO GET MAKER FEE RATE
function getMakerRate(bytes32 _tradePairId) public view returns (uint) {
return tradePairs.getMakerRate(_tradePairId);
}
// DEPLOYMENT ACCOUNT FUNCTION TO GET TAKER FEE RATE
function getTakerRate(bytes32 _tradePairId) public view returns (uint) {
return tradePairs.getTakerRate(_tradePairId);
}
// DEPLOYMENT ACCOUNT FUNCTION TO SET PORTFOLIO FOR THE EXCHANGE
function setPortfolio(IPortfolio _portfolio) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-05");
emit PortfolioSet(portfolio, _portfolio);
portfolio = _portfolio;
}
// FRONTEND FUNCTION TO GET PORTFOLIO
function getPortfolio() public view returns(IPortfolio) {
return portfolio;
}
// DEPLOYMENT ACCOUNT FUNCTION TO SET TRADEPAIRS FOR THE EXCHANGE
function setTradePairs(ITradePairs _tradePairs) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-06");
emit TradePairsSet(tradePairs, _tradePairs);
tradePairs = _tradePairs;
}
// FRONTEND FUNCTION TO GET TRADEPAIRS
function getTradePairsAddr() public view returns(ITradePairs) {
return tradePairs;
}
// DEPLOYMENT ACCOUNT FUNCTION TO ADD A NEW TRADEPAIR
function addTradePair(bytes32 _tradePairId,
address _baseAssetAddr, uint8 _baseDisplayDecimals,
address _quoteAssetAddr, uint8 _quoteDisplayDecimals,
uint _minTradeAmount, uint _maxTradeAmount)
public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-07");
(bytes32 _baseAssetSymbol, uint8 _baseAssetDecimals) = getAssetMeta(_baseAssetAddr);
(bytes32 _quoteAssetSymbol, uint8 _quoteAssetDecimals) = getAssetMeta(_quoteAssetAddr);
// check if base asset is native AVAX, if not it is ERC20 and add it
if (_baseAssetSymbol != bytes32("AVAX")) {
//Only the base token can be an auction TOKEN
portfolio.addToken(_baseAssetSymbol, IERC20MetadataUpgradeable(_baseAssetAddr));
}
// check if quote asset is native AVAX, if not it is ERC20 and add it
if (_quoteAssetSymbol != bytes32("AVAX")) {
portfolio.addToken(_quoteAssetSymbol, IERC20MetadataUpgradeable(_quoteAssetAddr));
}
tradePairs.addTradePair(_tradePairId,
_baseAssetSymbol, _baseAssetDecimals, _baseDisplayDecimals,
_quoteAssetSymbol, _quoteAssetDecimals, _quoteDisplayDecimals,
_minTradeAmount, _maxTradeAmount);
}
function getAssetMeta(address _assetAddr) private view returns (bytes32 _symbol, uint8 _decimals) {
if (_assetAddr == address(0)) {
return (bytes32("AVAX"), 18);
} else {
IERC20MetadataUpgradeable _asset = IERC20MetadataUpgradeable(_assetAddr);
return (StringLibrary.stringToBytes32(_asset.symbol()), _asset.decimals());
}
}
// DEPLOYMENT ACCOUNT FUNCTION TO PAUSE AND UNPAUSE THE PORTFOLIO CONTRACT - AFFECTS ALL DEPOSIT AND WITHDRAW FUNCTIONS
function pausePortfolio(bool _paused) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-08");
if (_paused) {
portfolio.pause();
} else {
portfolio.unpause();
}
}
// DEPLOYMENT ACCOUNT FUNCTION TO DISABLE ONLY DEPOSIT FUNCTIONS
function pauseDeposit(bool _paused) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-09");
portfolio.pauseDeposit(_paused);
}
// DEPLOYMENT ACCOUNT FUNCTION TO PAUSE AND UNPAUSE THE TRADEPAIRS CONTRACT
// AFFECTS BOTH ADDORDER AND CANCELORDER FUNCTIONS FOR ALL TRADE PAIRS
function pauseTrading(bool _tradingPaused) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-10");
if (_tradingPaused) {
tradePairs.pause();
} else {
tradePairs.unpause();
}
}
function pauseForUpgrade(bool _paused) public {
pausePortfolio(_paused);
pauseTrading(_paused);
}
// DEPLOYMENT ACCOUNT FUNCTION TO PAUSE AND UNPAUSE THE TRADEPAIRS CONTRACT
// AFFECTS BOTH ADDORDER AND CANCELORDER FUNCTIONS FOR A SELECTED TRADE PAIR
function pauseTradePair(bytes32 _tradePairId, bool _tradePairPaused) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-11");
tradePairs.pauseTradePair(_tradePairId, _tradePairPaused);
}
// DEPLOYMENT ACCOUNT FUNCTION TO DISABLE ONLY ADDORDER FUNCTION FOR A TRADEPAIR
function pauseAddOrder(bytes32 _tradePairId, bool _addOrderPaused) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-12");
tradePairs.pauseAddOrder(_tradePairId, _addOrderPaused);
}
// DEPLOYMENT ACCOUNT FUNCTION TO ADD AN ORDER TYPE TO A TRADEPAIR
function addOrderType(bytes32 _tradePairId, ITradePairs.Type1 _type) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-13");
tradePairs.addOrderType(_tradePairId, _type);
}
// DEPLOYMENT ACCOUNT FUNCTION TO REMOVE AN ORDER TYPE FROM A TRADEPAIR
function removeOrderType(bytes32 _tradePairId, ITradePairs.Type1 _type) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-14");
tradePairs.removeOrderType(_tradePairId, _type);
}
// DEPLOYMENT ACCOUNT FUNCTION TO SET MIN TRADE AMOUNT FOR A TRADEPAIR
function setMinTradeAmount(bytes32 _tradePairId, uint _minTradeAmount) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-15");
tradePairs.setMinTradeAmount(_tradePairId, _minTradeAmount);
}
// FRONTEND FUNCTION TO GET MIN TRADE AMOUNT
function getMinTradeAmount(bytes32 _tradePairId) public view returns (uint) {
return tradePairs.getMinTradeAmount(_tradePairId);
}
// DEPLOYMENT ACCOUNT FUNCTION TO SET MAX TRADE AMOUNT FOR A TRADEPAIR
function setMaxTradeAmount(bytes32 _tradePairId, uint _maxTradeAmount) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-16");
tradePairs.setMaxTradeAmount(_tradePairId, _maxTradeAmount);
}
// FRONTEND FUNCTION TO GET MAX TRADE AMOUNT
function getMaxTradeAmount(bytes32 _tradePairId) public view returns (uint) {
return tradePairs.getMaxTradeAmount(_tradePairId);
}
// FRONTEND FUNCTION TO SET DISPLAY DECIMALS
function setDisplayDecimals(bytes32 _tradePairId, uint8 _displayDecimals, bool _isBase) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-17");
tradePairs.setDisplayDecimals(_tradePairId, _displayDecimals, _isBase);
}
// FRONTEND FUNCTION TO GET DISPLAY DECIMALS
function getDisplayDecimals(bytes32 _tradePairId, bool _isBase) public view returns(uint8) {
return tradePairs.getDisplayDecimals(_tradePairId, _isBase);
}
// FRONTEND FUNCTION TO GET DECIMALS
function getDecimals(bytes32 _tradePairId, bool _isBase) public view returns(uint8) {
return tradePairs.getDecimals(_tradePairId, _isBase);
}
// FRONTEND FUNCTION TO GET DECIMALS
function getSymbol(bytes32 _tradePairId, bool _isBase) public view returns(bytes32) {
return tradePairs.getSymbol(_tradePairId, _isBase);
}
// DEPLOYMENT ACCOUNT FUNCTION TO SET ALLOWED SLIPPAGE PERCENT
function setAllowedSlippagePercent(bytes32 _tradePairId, uint8 _allowedSlippagePercent) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-18");
tradePairs.setAllowedSlippagePercent(_tradePairId, _allowedSlippagePercent);
}
// DEPLOYMENT ACCOUNT FUNCTION TO GET ALLOWED SLIPPAGE PERCENT
function getAllowedSlippagePercent(bytes32 _tradePairId) public view returns (uint8) {
return tradePairs.getAllowedSlippagePercent(_tradePairId);
}
// DEPLOYMENT ACCOUNT FUNCTION TO ADD A NEW TOKEN
// NEEDS TO BE CALLED ONLY AFTER PORTFOLIO IS SET FOR EXCHANGE AND PORTFOLIO OWNERSHIP IS CHANGED TO EXCHANGE
function addToken(bytes32 _symbol, IERC20Upgradeable _token) public {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "E-OACC-19");
portfolio.addToken(_symbol, _token);
}
fallback() external {}
// utility function to convert string to bytes32
function stringToBytes32(string memory _string) public pure returns (bytes32 result) {
return _string.stringToBytes32();
}
// utility function to convert bytes32 to string
function bytes32ToString(bytes32 _bytes32) public pure returns (string memory) {
return _bytes32.bytes32ToString();
}
}
Last updated