分享一个简单的DEX项目代码及文档
Dex.top项目源码及文档分享
// DEx.top - Instant Trading on Chain
//
// Author: DEx.top Team
pragma solidity 0.4.21;
pragma experimental "v0.5.0";
interface Token {
function transfer(address to, uint256 value) external returns (bool success);
function transferFrom(address from, address to, uint256 value) external returns (bool success);
}
contract Dex2 {
//------------------------------ Struct Definitions: ---------------------------------------------
struct TokenInfo {
string symbol; // e.g., "ETH", "ADX"
address tokenAddr; // ERC20 token address
uint64 scaleFactor; // <original token amount> = <scaleFactor> x <DEx amountE8> / 1e8
uint minDeposit; // mininum deposit (original token amount) allowed for this token
}
struct TraderInfo {
address withdrawAddr;
uint8 feeRebatePercent; // range: [0, 100]
}
struct TokenAccount {
uint64 balanceE8; // available amount for trading
uint64 pendingWithdrawE8; // the amount to be transferred out from this contract to the trader
}
struct Order {
uint32 pairId; // <cashId>(16) <stockId>(16)
uint8 action; // 0 means BUY; 1 means SELL
uint8 ioc; // 0 means a regular order; 1 means an immediate-or-cancel (IOC) order
uint64 priceE8;
uint64 amountE8;
uint64 expireTimeSec;
}
struct Deposit {
address traderAddr;
uint16 tokenCode;
uint64 pendingAmountE8; // amount to be confirmed for trading purpose
}
struct DealInfo {
uint16 stockCode; // stock token code
uint16 cashCode; // cash token code
uint64 stockDealAmountE8;
uint64 cashDealAmountE8;
}
struct ExeStatus {
uint64 logicTimeSec; // logic timestamp for checking order expiration
uint64 lastOperationIndex; // index of the last executed operation
}
//----------------- Constants: -------------------------------------------------------------------
uint constant MAX_UINT256 = 2**256 - 1;
uint16 constant MAX_FEE_RATE_E4 = 60; // upper limit of fee rate is 0.6% (60 / 1e4)
// <original ETH amount in Wei> = <DEx amountE8> * <ETH_SCALE_FACTOR> / 1e8
uint64 constant ETH_SCALE_FACTOR = 10**18;
uint8 constant ACTIVE = 0;
uint8 constant CLOSED = 2;
bytes32 constant HASHTYPES =
keccak256('string title', 'address market_address', 'uint64 nonce', 'uint64 expire_time_sec',
'uint64 amount_e8', 'uint64 price_e8', 'uint8 immediate_or_cancel', 'uint8 action',
'uint16 cash_token_code', 'uint16 stock_token_code');
//----------------- States that cannot be changed once set: --------------------------------------
address public admin; // admin address, and it cannot be changed
mapping (uint16 => TokenInfo) public tokens; // mapping of token code to token information
//----------------- Other states: ----------------------------------------------------------------
uint8 public marketStatus; // market status: 0 - Active; 1 - Suspended; 2 - Closed
uint16 public makerFeeRateE4; // maker fee rate (* 10**4)
uint16 public takerFeeRateE4; // taker fee rate (* 10**4)
uint16 public withdrawFeeRateE4; // withdraw fee rate (* 10**4)
uint64 public lastDepositIndex; // index of the last deposit operation
ExeStatus public exeStatus; // status of operation execution
mapping (address => TraderInfo) public traders; // mapping of trade address to trader information
mapping (uint176 => TokenAccount) public accounts; // mapping of trader token key to its account information
mapping (uint224 => Order) public orders; // mapping of order key to order information
mapping (uint64 => Deposit) public deposits; // mapping of deposit index to deposit information
//------------------------------ Dex2 Events: ----------------------------------------------------
event DeployMarketEvent();
event ChangeMarketStatusEvent(uint8 status);
event SetTokenInfoEvent(uint16 tokenCode, string symbol, address tokenAddr, uint64 scaleFactor, uint minDeposit);
event SetWithdrawAddrEvent(address trader, address withdrawAddr);
event DepositEvent(address trader, uint16 tokenCode, string symbol, uint64 amountE8, uint64 depositIndex);
event WithdrawEvent(address trader, uint16 tokenCode, string symbol, uint64 amountE8, uint64 lastOpIndex);
event TransferFeeEvent(uint16 tokenCode, uint64 amountE8, address toAddr);
// `balanceE8` is the total balance after this deposit confirmation
event ConfirmDepositEvent(address trader, uint16 tokenCode, uint64 balanceE8);
// `amountE8` is the post-fee initiated withdraw amount
// `pendingWithdrawE8` is the total pending withdraw amount after this withdraw initiation
event InitiateWithdrawEvent(address trader, uint16 tokenCode, uint64 amountE8, uint64 pendingWithdrawE8);
event MatchOrdersEvent(address trader1, uint64 nonce1, address trader2, uint64 nonce2);
event HardCancelOrderEvent(address trader, uint64 nonce);
event SetFeeRatesEvent(uint16 makerFeeRateE4, uint16 takerFeeRateE4, uint16 withdrawFeeRateE4);
event SetFeeRebatePercentEvent(address trader, uint8 feeRebatePercent);
//------------------------------ Contract Initialization: ----------------------------------------
function Dex2(address admin_) public {
admin = admin_;
setTokenInfo(0 /*tokenCode*/, "ETH", 0 /*tokenAddr*/, ETH_SCALE_FACTOR, 0 /*minDeposit*/);
emit DeployMarketEvent();
}
//------------------------------ External Functions: ---------------------------------------------
function() external {
revert();
}
// Change the market status of DEX.
function changeMarketStatus(uint8 status_) external {
if (msg.sender != admin) revert();
if (marketStatus == CLOSED) revert(); // closed is forever
marketStatus = status_;
emit ChangeMarketStatusEvent(status_);
}
// Each trader can specify a withdraw address (but cannot change it later). Once a trader's
// withdraw address is set, following withdrawals of this trader will go to the withdraw address
// instead of the trader's address.
function setWithdrawAddr(address withdrawAddr) external {
if (withdrawAddr == 0) revert();
if (traders[msg.sender].withdrawAddr != 0) revert(); // cannot change withdrawAddr once set
traders[msg.sender].withdrawAddr = withdrawAddr;
emit SetWithdrawAddrEvent(msg.sender, withdrawAddr);
}
// Deposit ETH from msg.sender for the given trader.
function depositEth(address traderAddr) external payable {
if (marketStatus != ACTIVE) revert();
if (traderAddr == 0) revert();
if (msg.value < tokens[0].minDeposit) revert();
if (msg.data.length != 4 + 32) revert(); // length condition of param count
uint64 pendingAmountE8 = uint64(msg.value / (ETH_SCALE_FACTOR / 10**8)); // msg.value is in Wei
if (pendingAmountE8 == 0) revert();
uint64 depositIndex = ++lastDepositIndex;
setDeposits(depositIndex, traderAddr, 0, pendingAmountE8);
emit DepositEvent(traderAddr, 0, "ETH", pendingAmountE8, depositIndex);
}
// Deposit token (other than ETH) from msg.sender for a specified trader.
//
// After the deposit has been confirmed enough times on the block