Skip to content

代币交易所系统

代币交易所是一个用于管理代币交易和流动性的系统。本教程将介绍如何实现一个安全可靠的交易所系统。

功能特性

  • 交易管理
  • 流动性管理
  • 价格发现
  • 手续费管理
  • 紧急处理

合约实现

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 代币交易所合约实现
 */
contract TokenExchange is Ownable, ReentrancyGuard, Pausable {
    using SafeMath for uint256;

    // 交易对信息
    struct PairInfo {
        address token0;          // 代币0
        address token1;          // 代币1
        uint256 reserve0;        // 储备0
        uint256 reserve1;        // 储备1
        uint256 totalSupply;     // 总供应量
        uint256 fee;            // 手续费率
        bool isActive;          // 是否激活
    }

    // 订单信息
    struct Order {
        address maker;          // 挂单者
        address token0;         // 卖出代币
        address token1;         // 买入代币
        uint256 amount0;        // 卖出数量
        uint256 amount1;        // 买入数量
        uint256 timestamp;      // 时间戳
        bool isActive;          // 是否激活
    }

    // 配置信息
    struct ExchangeConfig {
        uint256 minAmount;      // 最小数量
        uint256 maxAmount;      // 最大数量
        uint256 baseFee;        // 基础手续费
        uint256 maxFee;         // 最大手续费
        bool requiresApproval;  // 是否需要审批
        bool isActive;          // 是否激活
    }

    // 状态变量
    mapping(bytes32 => PairInfo) public pairs;                    // 交易对
    mapping(bytes32 => Order) public orders;                      // 订单
    mapping(address => mapping(address => uint256)) public liquidity;  // 流动性
    mapping(address => bool) public operators;                    // 操作员
    ExchangeConfig public config;                                // 配置信息

    // 事件
    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(
        uint256 _minAmount,
        uint256 _maxAmount,
        uint256 _baseFee,
        uint256 _maxFee
    ) {
        config = ExchangeConfig({
            minAmount: _minAmount,
            maxAmount: _maxAmount,
            baseFee: _baseFee,
            maxFee: _maxFee,
            requiresApproval: true,
            isActive: true
        });
    }

    /**
     * @dev 创建交易对
     */
    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 添加流动性
     */
    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 移除流动性
     */
    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 创建订单
     */
    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 执行订单
     */
    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 取消订单
     */
    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 获取交易对信息
     */
    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 获取订单信息
     */
    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 计算交易金额
     */
    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 设置操作员
     */
    function setOperator(address _operator, bool _status) external onlyOwner {
        operators[_operator] = _status;
        emit OperatorUpdated(_operator, _status);
    }

    /**
     * @dev 更新配置
     */
    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 暂停/恢复合约
     */
    function setPaused(bool _paused) external onlyOwner {
        if (_paused) {
            _pause();
        } else {
            _unpause();
        }
    }

    /**
     * @dev 紧急提取
     */
    function emergencyWithdraw(
        address _token,
        address _to,
        uint256 _amount
    ) external onlyOwner {
        require(_to != address(0), "Invalid address");
        IERC20(_token).transfer(_to, _amount);
    }

    /**
     * @dev 检查是否是操作员
     */
    modifier onlyOperator() {
        require(operators[msg.sender] || msg.sender == owner(), "Not operator");
        _;
    }
}

关键概念

交易管理

交易功能包括:

  • 订单创建
  • 订单执行
  • 订单取消
  • 价格发现

流动性管理

流动性功能包括:

  • 添加流动性
  • 移除流动性
  • 流动性计算
  • 储备管理

手续费管理

手续费功能包括:

  • 费率设置
  • 费用计算
  • 费用分配
  • 收益分配

安全考虑

  1. 交易安全

    • 订单验证
    • 价格验证
    • 数量验证
    • 状态检查
  2. 流动性安全

    • 储备验证
    • 比例检查
    • 余额验证
    • 状态保护
  3. 系统安全

    • 权限控制
    • 暂停机制
    • 重入防护
    • 状态同步
  4. 升级安全

    • 配置更新
    • 费率调整
    • 状态迁移
    • 紧急处理

最佳实践

  1. 交易管理

    • 订单验证
    • 价格管理
    • 状态追踪
    • 异常处理
  2. 流动性管理

    • 储备管理
    • 比例控制
    • 余额验证
    • 状态管理
  3. 风险管理

    • 价格监控
    • 异常检测
    • 风险预警
    • 应急处理
  4. 系统维护

    • 参数优化
    • 性能监控
    • 安全审计
    • 升级预案

扩展功能

  1. 多币种支持
  2. 限价订单
  3. 市价订单
  4. 自动做市
  5. 价格预言机

应用场景

  1. 代币交易

    • 限价交易
    • 市价交易
    • 流动性提供
    • 做市交易
  2. 资产管理

    • 流动性管理
    • 资产配置
    • 风险控制
    • 收益优化
  3. 市场管理

    • 价格发现
    • 流动性维护
    • 市场稳定
    • 风险控制

总结

代币交易所系统是DeFi生态的重要基础设施。通过本教程,你可以:

  • 实现交易功能
  • 管理流动性
  • 优化交易机制
  • 提供安全保护

常见问题解答(FAQ)

基础概念

Q: 什么是代币交易所?

A: 代币交易所是一种去中心化交易机制,主要特点包括:

  • 自动化代币交换
  • 流动性池管理
  • 价格自动发现
  • 无需对手方
  • 透明公平交易

Q: 交易所有哪些类型?

A: 主要类型包括:

  • 自动做市商(AMM)
  • 订单簿模式
  • 混合交易模式
  • 稳定币交易对
  • 跨链交易所

操作相关

Q: 如何使用代币交易所?

A: 使用步骤包括:

  • 连接钱包
  • 选择交易对
  • 设置交易参数
  • 确认交易
  • 等待完成

Q: 如何提供流动性?

A: 操作步骤包括:

  • 准备代币对
  • 选择流动性池
  • 设置注入比例
  • 确认添加
  • 获取LP代币

安全相关

Q: 交易所有哪些风险?

A: 主要风险包括:

  • 无常损失风险
  • 价格滑点
  • 智能合约漏洞
  • 流动性不足
  • 市场操纵

Q: 如何确保交易安全?

A: 安全措施包括:

  • 设置滑点保护
  • 限制交易规模
  • 多重签名控制
  • 价格预言机
  • 紧急暂停机制

Released under the MIT License by Vogeb.