Exchange peer-to-peer

Description:

A simple exemple to create a smart contract who can exchange cryptos peer-to-peer (user to user) for a decentralized exchange.
On Etherscan click on "read contract" to available exchange, and how much they are.
Still on Etherscan, you can click on "write contract" to create an offer, cancel and order, or fill an order.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Brut code:

// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; /// @title DecentralizedExchange /// @notice Permet aux utilisateurs de créer et remplir des offres d’échange entre tokens ERC20. contract DecentralizedExchange is ReentrancyGuard { using SafeERC20 for IERC20; uint256 public orderCounter; struct Order { uint256 id; // Identifiant unique de l'ordre address maker; // Adresse du créateur de l'ordre address tokenOffered; // Adresse du token proposé par le maker uint256 amountOffered; // Quantité de tokens offerts address tokenRequested; // Adresse du token demandé en échange uint256 amountRequested; // Quantité de tokens demandés uint256 expirationTime; // Timestamp d'expiration de l'ordre bool active; // Indique si l'ordre est toujours actif } // Mapping des ordres par identifiant mapping(uint256 => Order) public orders; // Événements pour le suivi des actions event OrderCreated( uint256 indexed id, address indexed maker, address tokenOffered, uint256 amountOffered, address tokenRequested, uint256 amountRequested, uint256 expirationTime ); event OrderCancelled(uint256 indexed id, address indexed maker); event OrderFilled(uint256 indexed id, address indexed maker, address indexed filler); /// @notice Crée une nouvelle offre d'échange /// @param _tokenOffered L'adresse du token que le maker offre (ex : WETH) /// @param _amountOffered La quantité de tokens offerts /// @param _tokenRequested L'adresse du token que le maker souhaite obtenir (ex : USDT) /// @param _amountRequested La quantité de tokens demandés en échange /// @param _expirationTime Timestamp d'expiration de l'ordre (doit être supérieur au timestamp courant) /// @return L'identifiant de l'ordre créé /// /// Avant d'appeler cette fonction, le maker doit avoir approuvé le transfert de _amountOffered de _tokenOffered vers ce contrat. function createOrder( address _tokenOffered, uint256 _amountOffered, address _tokenRequested, uint256 _amountRequested, uint256 _expirationTime ) external returns (uint256) { require(_tokenOffered != address(0) && _tokenRequested != address(0), "Adresse token invalide"); require(_amountOffered > 0 && _amountRequested > 0, "Les montants doivent etre superieurs a zero"); require(_expirationTime > block.timestamp, "Expiration invalide"); // Transfert des tokens offerts depuis le maker vers le contrat (mise en escrow) IERC20(_tokenOffered).safeTransferFrom(msg.sender, address(this), _amountOffered); orderCounter++; orders[orderCounter] = Order({ id: orderCounter, maker: msg.sender, tokenOffered: _tokenOffered, amountOffered: _amountOffered, tokenRequested: _tokenRequested, amountRequested: _amountRequested, expirationTime: _expirationTime, active: true }); emit OrderCreated(orderCounter, msg.sender, _tokenOffered, _amountOffered, _tokenRequested, _amountRequested, _expirationTime); return orderCounter; } /// @notice Annule un ordre actif. Seul le maker peut annuler son propre ordre. /// @param _orderId L'identifiant de l'ordre à annuler function cancelOrder(uint256 _orderId) external nonReentrant { Order storage order = orders[_orderId]; require(order.active, "L'ordre n'est pas actif"); require(order.maker == msg.sender, "Seul le createur peut annuler"); order.active = false; // Retour des tokens offerts au maker IERC20(order.tokenOffered).safeTransfer(order.maker, order.amountOffered); emit OrderCancelled(_orderId, msg.sender); } /// @notice Permet à un utilisateur de remplir un ordre actif. /// @param _orderId L'identifiant de l'ordre à remplir /// /// Le filler doit avoir approuvé le transfert de _amountRequested de _tokenRequested vers le maker. function fillOrder(uint256 _orderId) external nonReentrant { Order storage order = orders[_orderId]; require(order.active, "L'ordre n'est pas actif"); require(block.timestamp < order.expirationTime, "L'ordre a expire"); // Marquer l'ordre comme inactif avant les transferts pour éviter les attaques de réentrance order.active = false; // Transfert des tokens demandés depuis le filler vers le maker IERC20(order.tokenRequested).safeTransferFrom(msg.sender, order.maker, order.amountRequested); // Transfert des tokens offerts depuis le contrat vers le filler IERC20(order.tokenOffered).safeTransfer(msg.sender, order.amountOffered); emit OrderFilled(_orderId, order.maker, msg.sender); } /// @notice Permet à quiconque d'expirer un ordre et de retourner les tokens au maker si l'ordre est expiré. /// @param _orderId L'identifiant de l'ordre à expirer function expireOrder(uint256 _orderId) external nonReentrant { Order storage order = orders[_orderId]; require(order.active, "L'ordre n'est pas actif"); require(block.timestamp >= order.expirationTime, "L'ordre n'est pas encore expire"); order.active = false; // Retour des tokens offerts au maker IERC20(order.tokenOffered).safeTransfer(order.maker, order.amountOffered); emit OrderCancelled(_orderId, order.maker); } }

Tags: Exchange, decentralized, peer-to-peer, token, coin

Submitted on: 2025-04-02 16:22:12


Comments

Log in to comment.

No comments yet.