// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /// @title Treasury — 资金托管合约 /// @notice 保障资金锁定、交易 Escrow、资金释放与费用分割 /// @dev 使用 Transparent Proxy 部署 contract Treasury is Initializable, AccessControlUpgradeable, ReentrancyGuardUpgradeable { bytes32 public constant SETTLER_ROLE = keccak256("SETTLER_ROLE"); bytes32 public constant GOVERNANCE_ROLE = keccak256("GOVERNANCE_ROLE"); IERC20 public stablecoin; address public platformFeeCollector; // 发行方保障资金(自愿缴纳,提升信用评级) mapping(address => uint256) public guaranteeFunds; // 发行方冻结的销售款(自愿,作为兑付保障) mapping(address => uint256) public frozenSalesRevenue; // Escrow 托管 mapping(uint256 => EscrowInfo) public escrows; struct EscrowInfo { address buyer; uint256 amount; bool released; bool refunded; } // --- Events --- event GuaranteeFundDeposited(address indexed issuer, uint256 amount); event GuaranteeFundWithdrawn(address indexed issuer, uint256 amount); event GuaranteeFundActivated(address indexed issuer, uint256 totalClaim); event SalesRevenueFrozen(address indexed issuer, uint256 amount); event SalesRevenueReleased(address indexed issuer, uint256 amount); event FundsEscrowed(uint256 indexed orderId, address indexed buyer, uint256 amount); event FundsReleased(uint256 indexed orderId, address indexed seller, uint256 amount, uint256 platformFee); event FundsRefunded(uint256 indexed orderId, address indexed buyer, uint256 amount); function initialize( address _stablecoin, address _platformFeeCollector, address admin ) external initializer { __AccessControl_init(); __ReentrancyGuard_init(); stablecoin = IERC20(_stablecoin); platformFeeCollector = _platformFeeCollector; _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(SETTLER_ROLE, admin); _grantRole(GOVERNANCE_ROLE, admin); } // ======================== // 保障资金管理 // ======================== /// @notice 发行方缴纳保障资金 function depositGuaranteeFund(uint256 amount) external nonReentrant { require(amount > 0, "Treasury: zero amount"); stablecoin.transferFrom(msg.sender, address(this), amount); guaranteeFunds[msg.sender] += amount; emit GuaranteeFundDeposited(msg.sender, amount); } /// @notice 发行方提取保障资金(需治理审批) function withdrawGuaranteeFund(address issuer, uint256 amount) external onlyRole(GOVERNANCE_ROLE) nonReentrant { require(guaranteeFunds[issuer] >= amount, "Treasury: insufficient guarantee"); guaranteeFunds[issuer] -= amount; stablecoin.transfer(issuer, amount); emit GuaranteeFundWithdrawn(issuer, amount); } /// @notice 发行方违约时启用保障资金赔付 function activateGuaranteeFund( address issuer, address[] calldata claimants, uint256[] calldata amounts ) external onlyRole(GOVERNANCE_ROLE) nonReentrant { require(claimants.length == amounts.length, "Treasury: length mismatch"); uint256 totalClaim = 0; for (uint256 i = 0; i < claimants.length; i++) { totalClaim += amounts[i]; } require(guaranteeFunds[issuer] >= totalClaim, "Treasury: insufficient guarantee fund"); guaranteeFunds[issuer] -= totalClaim; for (uint256 i = 0; i < claimants.length; i++) { stablecoin.transfer(claimants[i], amounts[i]); } emit GuaranteeFundActivated(issuer, totalClaim); } // ======================== // 销售款冻结 // ======================== /// @notice 发行方冻结销售款(自愿,作为兑付保障) function freezeSalesRevenue(uint256 amount) external nonReentrant { require(amount > 0, "Treasury: zero amount"); stablecoin.transferFrom(msg.sender, address(this), amount); frozenSalesRevenue[msg.sender] += amount; emit SalesRevenueFrozen(msg.sender, amount); } /// @notice 释放冻结销售款(需治理审批) function releaseSalesRevenue(address issuer, uint256 amount) external onlyRole(GOVERNANCE_ROLE) nonReentrant { require(frozenSalesRevenue[issuer] >= amount, "Treasury: insufficient frozen revenue"); frozenSalesRevenue[issuer] -= amount; stablecoin.transfer(issuer, amount); emit SalesRevenueReleased(issuer, amount); } // ======================== // 交易 Escrow // ======================== /// @notice 交易资金托管(原子交换中间态) function escrow(uint256 orderId, address buyer, uint256 amount) external onlyRole(SETTLER_ROLE) nonReentrant { require(amount > 0, "Treasury: zero escrow"); require(escrows[orderId].amount == 0, "Treasury: escrow exists"); stablecoin.transferFrom(buyer, address(this), amount); escrows[orderId] = EscrowInfo({ buyer: buyer, amount: amount, released: false, refunded: false }); emit FundsEscrowed(orderId, buyer, amount); } /// @notice 释放托管资金给卖方 function release( uint256 orderId, address seller, uint256 amount, uint256 platformFee ) external onlyRole(SETTLER_ROLE) nonReentrant { EscrowInfo storage info = escrows[orderId]; require(info.amount > 0, "Treasury: no escrow"); require(!info.released && !info.refunded, "Treasury: already settled"); require(amount + platformFee <= info.amount, "Treasury: exceeds escrow"); info.released = true; // 卖方收款 stablecoin.transfer(seller, amount); // 平台手续费归集 if (platformFee > 0) { stablecoin.transfer(platformFeeCollector, platformFee); } emit FundsReleased(orderId, seller, amount, platformFee); } /// @notice 退回托管资金给买方 function refundEscrow(uint256 orderId) external onlyRole(SETTLER_ROLE) nonReentrant { EscrowInfo storage info = escrows[orderId]; require(info.amount > 0, "Treasury: no escrow"); require(!info.released && !info.refunded, "Treasury: already settled"); info.refunded = true; stablecoin.transfer(info.buyer, info.amount); emit FundsRefunded(orderId, info.buyer, info.amount); } // ======================== // 管理 // ======================== /// @notice 更新平台手续费收集地址 function setPlatformFeeCollector(address _collector) external onlyRole(GOVERNANCE_ROLE) { require(_collector != address(0), "Treasury: zero address"); platformFeeCollector = _collector; } }