gcx/blockchain/genex-contracts/src/Treasury.sol

187 lines
7.1 KiB
Solidity

// 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;
}
}