Token Exchange System
The token exchange system is a system for managing token trading and liquidity. This tutorial will explain how to implement a secure and reliable exchange system.
Features
- Trade Management
- Liquidity Management
- Price Discovery
- Fee Management
- Emergency Handling
Contract Implementation
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
/**
* @title TokenExchange
* @dev Token exchange contract implementation
*/
contract TokenExchange is Ownable, ReentrancyGuard, Pausable {
using SafeMath for uint256;
// Pair information
struct PairInfo {
address token0; // Token 0
address token1; // Token 1
uint256 reserve0; // Reserve 0
uint256 reserve1; // Reserve 1
uint256 totalSupply; // Total supply
uint256 fee; // Fee rate
bool isActive; // Is active
}
// Order information
struct Order {
address maker; // Order maker
address token0; // Sell token
address token1; // Buy token
uint256 amount0; // Sell amount
uint256 amount1; // Buy amount
uint256 timestamp; // Timestamp
bool isActive; // Is active
}
// Configuration information
struct ExchangeConfig {
uint256 minAmount; // Minimum amount
uint256 maxAmount; // Maximum amount
uint256 baseFee; // Base fee
uint256 maxFee; // Maximum fee
bool requiresApproval; // Requires approval
bool isActive; // Is active
}
// State variables
mapping(bytes32 => PairInfo) public pairs; // Trading pairs
mapping(bytes32 => Order) public orders; // Orders
mapping(address => mapping(address => uint256)) public liquidity; // Liquidity
mapping(address => bool) public operators; // Operators
ExchangeConfig public config; // Configuration
// Events
event PairCreated(bytes32 indexed pairId, address indexed token0, address indexed token1);
event LiquidityAdded(bytes32 indexed pairId, address indexed provider, uint256 amount0, uint256 amount1);
event LiquidityRemoved(bytes32 indexed pairId, address indexed provider, uint256 amount0, uint256 amount1);
event OrderCreated(bytes32 indexed orderId, address indexed maker, uint256 amount0, uint256 amount1);
event OrderExecuted(bytes32 indexed orderId, address indexed taker, uint256 amount0, uint256 amount1);
event OrderCancelled(bytes32 indexed orderId);
event OperatorUpdated(address indexed operator, bool status);
event ConfigUpdated(uint256 minAmount, uint256 maxAmount, uint256 baseFee);
/**
* @dev Constructor
*/
constructor(
uint256 _minAmount,
uint256 _maxAmount,
uint256 _baseFee,
uint256 _maxFee
) {
config = ExchangeConfig({
minAmount: _minAmount,
maxAmount: _maxAmount,
baseFee: _baseFee,
maxFee: _maxFee,
requiresApproval: true,
isActive: true
});
}
/**
* @dev Create trading pair
*/
function createPair(
address _token0,
address _token1,
uint256 _fee
) external onlyOperator whenNotPaused returns (bytes32) {
require(_token0 != address(0) && _token1 != address(0), "Invalid tokens");
require(_token0 != _token1, "Same tokens");
require(_fee <= config.maxFee, "Fee too high");
bytes32 pairId = keccak256(abi.encodePacked(_token0, _token1));
require(!pairs[pairId].isActive, "Pair exists");
pairs[pairId] = PairInfo({
token0: _token0,
token1: _token1,
reserve0: 0,
reserve1: 0,
totalSupply: 0,
fee: _fee,
isActive: true
});
emit PairCreated(pairId, _token0, _token1);
return pairId;
}
/**
* @dev Add liquidity
*/
function addLiquidity(
bytes32 _pairId,
uint256 _amount0,
uint256 _amount1
) external nonReentrant whenNotPaused returns (uint256) {
PairInfo storage pair = pairs[_pairId];
require(pair.isActive, "Pair not active");
require(_amount0 >= config.minAmount && _amount1 >= config.minAmount, "Amount too low");
require(_amount0 <= config.maxAmount && _amount1 <= config.maxAmount, "Amount too high");
uint256 liquidity0 = _amount0;
uint256 liquidity1 = _amount1;
if (pair.totalSupply > 0) {
require(
_amount0.mul(pair.reserve1) == _amount1.mul(pair.reserve0),
"Invalid ratio"
);
}
require(
IERC20(pair.token0).transferFrom(msg.sender, address(this), _amount0),
"Transfer failed"
);
require(
IERC20(pair.token1).transferFrom(msg.sender, address(this), _amount1),
"Transfer failed"
);
pair.reserve0 = pair.reserve0.add(_amount0);
pair.reserve1 = pair.reserve1.add(_amount1);
pair.totalSupply = pair.totalSupply.add(liquidity0);
liquidity[_pairId][msg.sender] = liquidity[_pairId][msg.sender].add(liquidity0);
emit LiquidityAdded(_pairId, msg.sender, _amount0, _amount1);
return liquidity0;
}
/**
* @dev Remove liquidity
*/
function removeLiquidity(
bytes32 _pairId,
uint256 _liquidity
) external nonReentrant whenNotPaused returns (uint256, uint256) {
PairInfo storage pair = pairs[_pairId];
require(pair.isActive, "Pair not active");
require(_liquidity > 0, "Invalid liquidity");
require(liquidity[_pairId][msg.sender] >= _liquidity, "Insufficient liquidity");
uint256 amount0 = _liquidity.mul(pair.reserve0).div(pair.totalSupply);
uint256 amount1 = _liquidity.mul(pair.reserve1).div(pair.totalSupply);
liquidity[_pairId][msg.sender] = liquidity[_pairId][msg.sender].sub(_liquidity);
pair.totalSupply = pair.totalSupply.sub(_liquidity);
pair.reserve0 = pair.reserve0.sub(amount0);
pair.reserve1 = pair.reserve1.sub(amount1);
require(
IERC20(pair.token0).transfer(msg.sender, amount0),
"Transfer failed"
);
require(
IERC20(pair.token1).transfer(msg.sender, amount1),
"Transfer failed"
);
emit LiquidityRemoved(_pairId, msg.sender, amount0, amount1);
return (amount0, amount1);
}
/**
* @dev Create order
*/
function createOrder(
address _token0,
address _token1,
uint256 _amount0,
uint256 _amount1
) external nonReentrant whenNotPaused returns (bytes32) {
require(_amount0 >= config.minAmount && _amount1 >= config.minAmount, "Amount too low");
require(_amount0 <= config.maxAmount && _amount1 <= config.maxAmount, "Amount too high");
bytes32 orderId = keccak256(abi.encodePacked(
block.timestamp,
msg.sender,
_token0,
_token1,
_amount0,
_amount1
));
orders[orderId] = Order({
maker: msg.sender,
token0: _token0,
token1: _token1,
amount0: _amount0,
amount1: _amount1,
timestamp: block.timestamp,
isActive: true
});
require(
IERC20(_token0).transferFrom(msg.sender, address(this), _amount0),
"Transfer failed"
);
emit OrderCreated(orderId, msg.sender, _amount0, _amount1);
return orderId;
}
/**
* @dev Execute order
*/
function executeOrder(
bytes32 _orderId
) external nonReentrant whenNotPaused {
Order storage order = orders[_orderId];
require(order.isActive, "Order not active");
require(msg.sender != order.maker, "Cannot execute own order");
require(
IERC20(order.token1).transferFrom(msg.sender, order.maker, order.amount1),
"Transfer failed"
);
require(
IERC20(order.token0).transfer(msg.sender, order.amount0),
"Transfer failed"
);
order.isActive = false;
emit OrderExecuted(_orderId, msg.sender, order.amount0, order.amount1);
}
/**
* @dev Cancel order
*/
function cancelOrder(bytes32 _orderId) external nonReentrant whenNotPaused {
Order storage order = orders[_orderId];
require(order.isActive, "Order not active");
require(msg.sender == order.maker, "Not order maker");
order.isActive = false;
require(
IERC20(order.token0).transfer(order.maker, order.amount0),
"Transfer failed"
);
emit OrderCancelled(_orderId);
}
/**
* @dev Get trading pair information
*/
function getPairInfo(bytes32 _pairId)
external
view
returns (
address token0,
address token1,
uint256 reserve0,
uint256 reserve1,
uint256 totalSupply,
uint256 fee,
bool isActive
)
{
PairInfo storage pair = pairs[_pairId];
return (
pair.token0,
pair.token1,
pair.reserve0,
pair.reserve1,
pair.totalSupply,
pair.fee,
pair.isActive
);
}
/**
* @dev Get order information
*/
function getOrderInfo(bytes32 _orderId)
external
view
returns (
address maker,
address token0,
address token1,
uint256 amount0,
uint256 amount1,
uint256 timestamp,
bool isActive
)
{
Order storage order = orders[_orderId];
return (
order.maker,
order.token0,
order.token1,
order.amount0,
order.amount1,
order.timestamp,
order.isActive
);
}
/**
* @dev Calculate trading amount
*/
function getAmountOut(
bytes32 _pairId,
uint256 _amountIn,
bool _isToken0
) external view returns (uint256) {
PairInfo storage pair = pairs[_pairId];
require(pair.isActive, "Pair not active");
require(_amountIn > 0, "Invalid amount");
uint256 reserveIn = _isToken0 ? pair.reserve0 : pair.reserve1;
uint256 reserveOut = _isToken0 ? pair.reserve1 : pair.reserve0;
uint256 amountInWithFee = _amountIn.mul(1000 - pair.fee);
uint256 numerator = amountInWithFee.mul(reserveOut);
uint256 denominator = reserveIn.mul(1000).add(amountInWithFee);
return numerator.div(denominator);
}
/**
* @dev Set operator
*/
function setOperator(address _operator, bool _status) external onlyOwner {
operators[_operator] = _status;
emit OperatorUpdated(_operator, _status);
}
/**
* @dev Update configuration
*/
function updateConfig(
uint256 _minAmount,
uint256 _maxAmount,
uint256 _baseFee,
uint256 _maxFee,
bool _requiresApproval
) external onlyOwner {
require(_maxAmount > _minAmount, "Invalid amounts");
require(_maxFee >= _baseFee, "Invalid fees");
config.minAmount = _minAmount;
config.maxAmount = _maxAmount;
config.baseFee = _baseFee;
config.maxFee = _maxFee;
config.requiresApproval = _requiresApproval;
emit ConfigUpdated(_minAmount, _maxAmount, _baseFee);
}
/**
* @dev Pause/unpause contract
*/
function setPaused(bool _paused) external onlyOwner {
if (_paused) {
_pause();
} else {
_unpause();
}
}
/**
* @dev Emergency withdrawal
*/
function emergencyWithdraw(
address _token,
address _to,
uint256 _amount
) external onlyOwner {
require(_to != address(0), "Invalid address");
IERC20(_token).transfer(_to, _amount);
}
/**
* @dev Check if it's an operator
*/
modifier onlyOperator() {
require(operators[msg.sender] || msg.sender == owner(), "Not operator");
_;
}
}
Key Concepts
Trade Management
Trade functions include:
- Order creation
- Order execution
- Order cancellation
- Price discovery
Liquidity Management
Liquidity functions include:
- Adding liquidity
- Removing liquidity
- Liquidity calculation
- Reserve management
Fee Management
Fee functions include:
- Fee rate setting
- Fee calculation
- Fee allocation
- Revenue allocation
Security Considerations
Trade security
- Order verification
- Price verification
- Amount verification
- Status check
Liquidity security
- Reserve verification
- Ratio check
- Balance verification
- Status protection
System security
- Permission control
- Pause mechanism
- Reentrancy protection
- Status synchronization
Upgrade security
- Configuration update
- Fee rate adjustment
- Status migration
- Emergency handling
Best Practices
Trade management
- Order verification
- Price management
- Status tracking
- Exception handling
Liquidity management
- Reserve management
- Ratio control
- Balance verification
- Status management
Risk management
- Price monitoring
- Exception detection
- Risk warning
- Emergency handling
System maintenance
- Parameter optimization
- Performance monitoring
- Security audit
- Upgrade plan
Extended Features
- Multi-token support
- Limit order
- Market order
- Automated market maker
- Price oracle
Application Scenarios
Token trading
- Limit order trading
- Market order trading
- Liquidity provision
- Market making
Asset management
- Liquidity management
- Asset allocation
- Risk control
- Revenue optimization
Market management
- Price discovery
- Liquidity maintenance
- Market stability
- Risk control
Summary
The token exchange system is an important infrastructure in the DeFi ecosystem. Through this tutorial, you can:
- Implement trade functions
- Manage liquidity
- Optimize trading mechanisms
- Provide security protection
Frequently Asked Questions (FAQ)
Basic Concepts
Q: What is a token exchange?
A: A token exchange is a decentralized trading mechanism, with the main features including:
- Automated token exchange
- Liquidity pool management
- Price automatic discovery
- No counterparty
- Transparent and fair trading
Q: What types of exchanges are there?
A: The main types include:
- Automated market maker (AMM)
- Order book mode
- Mixed trading mode
- Stablecoin trading pairs
- Cross-chain exchanges
Operational Related
Q: How to use a token exchange?
A: The steps include:
- Connecting a wallet
- Selecting a trading pair
- Setting trading parameters
- Confirming the transaction
- Waiting for completion
Q: How to provide liquidity?
A: The steps include:
- Preparing token pairs
- Selecting a liquidity pool
- Setting the injection ratio
- Confirming the addition
- Obtaining LP tokens
Security Related
Q: What risks are there in trading?
A: The main risks include:
- Impermanent loss risk
- Price slippage
- Smart contract vulnerabilities
- Insufficient liquidity
- Market manipulation
Q: How to ensure trade security?
A: Security measures include:
- Setting slippage protection
- Limiting trading volume
- Multi-signature control
- Price oracle
- Emergency pause mechanism
Technical Related
Q: What is AMM?
A: Automated Market Maker (AMM) is a decentralized trading mechanism with the following features:
- Automated price discovery
- Constant product formula
- No order book needed
- Continuous liquidity
- Permissionless trading
Q: What is impermanent loss?
A: Impermanent loss refers to:
- Value difference between holding tokens and providing liquidity
- Caused by price changes in token pairs
- Can be mitigated by trading fees
- More significant in volatile pairs
- Temporary until liquidity is removed
Development Related
Q: How to optimize gas consumption?
A: Optimization methods include:
- Batch processing
- State variable optimization
- Event optimization
- Function optimization
- Storage optimization
Q: How to handle emergencies?
A: Emergency handling includes:
- Emergency pause
- Fund withdrawal
- Parameter adjustment
- Bug fixes
- System recovery
Development Guide
Environment Setup
Development tools
- Hardhat/Truffle
- Web3.js/Ethers.js
- Solidity
- OpenZeppelin
- Testing frameworks
Contract deployment
- Network selection
- Gas optimization
- Parameter configuration
- Security verification
- Monitoring setup
Testing Guide
Unit testing
- Function testing
- Parameter validation
- Error handling
- Event verification
- State checking
Integration testing
- Contract interaction
- System workflow
- Edge cases
- Performance testing
- Security testing
Deployment Guide
Preparation
- Code audit
- Gas estimation
- Parameter setting
- Network selection
- Documentation
Deployment steps
- Contract deployment
- Parameter initialization
- Permission setting
- Function verification
- Monitoring setup
Maintenance Guide
Regular maintenance
- Performance monitoring
- Security scanning
- Parameter adjustment
- Bug fixing
- Version upgrade
Emergency response
- Issue detection
- System pause
- Problem analysis
- Solution implementation
- System recovery
References
Technical documentation
- Solidity docs
- OpenZeppelin docs
- Uniswap docs
- Web3 docs
- Testing frameworks
Security resources
- Audit reports
- Security best practices
- Known vulnerabilities
- Security tools
- Emergency procedures
Development tools
- Smart contract tools
- Testing tools
- Deployment tools
- Monitoring tools
- Analysis tools