Skip to content

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

solidity
// 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

  1. Trade security

    • Order verification
    • Price verification
    • Amount verification
    • Status check
  2. Liquidity security

    • Reserve verification
    • Ratio check
    • Balance verification
    • Status protection
  3. System security

    • Permission control
    • Pause mechanism
    • Reentrancy protection
    • Status synchronization
  4. Upgrade security

    • Configuration update
    • Fee rate adjustment
    • Status migration
    • Emergency handling

Best Practices

  1. Trade management

    • Order verification
    • Price management
    • Status tracking
    • Exception handling
  2. Liquidity management

    • Reserve management
    • Ratio control
    • Balance verification
    • Status management
  3. Risk management

    • Price monitoring
    • Exception detection
    • Risk warning
    • Emergency handling
  4. System maintenance

    • Parameter optimization
    • Performance monitoring
    • Security audit
    • Upgrade plan

Extended Features

  1. Multi-token support
  2. Limit order
  3. Market order
  4. Automated market maker
  5. Price oracle

Application Scenarios

  1. Token trading

    • Limit order trading
    • Market order trading
    • Liquidity provision
    • Market making
  2. Asset management

    • Liquidity management
    • Asset allocation
    • Risk control
    • Revenue optimization
  3. 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

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

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

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

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

  1. Development tools

    • Hardhat/Truffle
    • Web3.js/Ethers.js
    • Solidity
    • OpenZeppelin
    • Testing frameworks
  2. Contract deployment

    • Network selection
    • Gas optimization
    • Parameter configuration
    • Security verification
    • Monitoring setup

Testing Guide

  1. Unit testing

    • Function testing
    • Parameter validation
    • Error handling
    • Event verification
    • State checking
  2. Integration testing

    • Contract interaction
    • System workflow
    • Edge cases
    • Performance testing
    • Security testing

Deployment Guide

  1. Preparation

    • Code audit
    • Gas estimation
    • Parameter setting
    • Network selection
    • Documentation
  2. Deployment steps

    • Contract deployment
    • Parameter initialization
    • Permission setting
    • Function verification
    • Monitoring setup

Maintenance Guide

  1. Regular maintenance

    • Performance monitoring
    • Security scanning
    • Parameter adjustment
    • Bug fixing
    • Version upgrade
  2. Emergency response

    • Issue detection
    • System pause
    • Problem analysis
    • Solution implementation
    • System recovery

References

  1. Technical documentation

    • Solidity docs
    • OpenZeppelin docs
    • Uniswap docs
    • Web3 docs
    • Testing frameworks
  2. Security resources

    • Audit reports
    • Security best practices
    • Known vulnerabilities
    • Security tools
    • Emergency procedures
  3. Development tools

    • Smart contract tools
    • Testing tools
    • Deployment tools
    • Monitoring tools
    • Analysis tools

Released under the MIT License by Vogeb.