🏛️ Hệ Thống Smart Contract GVI Network

Kiến trúc Kỹ thuật — Tuân thủ Pháp lý Việt Nam


Phiên bản: 3.0.0 Ngày cập nhật: 2025 Đơn vị: GoldVN Invest — https://goldvninvest.online Công nghệ: Solidity 0.8.20 · BSC Mainnet · Hardhat Hành lang pháp lý: Nghị quyết 05/2025/NQ-CP · Luật 71/2025/QH15


📁 Vị trí file trong dự án

backend/ecosystem/smart-contracts/gvi/
├── contracts/
│   ├── GIVToken.sol              ← Token quản trị nội bộ (GIV)
│   ├── VNLToken.sol              ← Stablecoin 1:1 VND — kết nối ngân hàng
│   ├── GIVGovernance.sol         ← dPoS oracle định giá GIV ±7%
│   ├── EmergencyCircuitBreaker.sol ← Cơ chế ngắt khẩn cấp (Bộ Tài chính)
│   └── InvestorWhitelist.sol     ← Kiểm soát KYC on-chain (Điều 6/7 NQ-05)
├── scripts/
│   ├── deploy.js
│   └── verify.js
├── hardhat.config.js
└── README.md

I. Căn cứ pháp lý & Mô hình vận hành

1.1 Hành lang pháp lý áp dụng

GVI Network là sàn giao dịch tài sản kỹ thuật số hoạt động trong khuôn khổ thí điểm 5 năm theo:

Văn bản Nội dung áp dụng
Nghị quyết 05/2025/NQ-CP Cơ chế thí điểm sàn giao dịch tài sản mã hóa tại Việt Nam
Luật 71/2025/QH15 Công nhận tài sản số, nghĩa vụ thuế, bảo vệ pháp lý
Luật AML/CFT Việt Nam Phòng chống rửa tiền, sàng lọc nhà đầu tư
TCVN 11930:2017 An toàn thông tin Cấp độ 4

1.2 Mô hình kinh doanh hợp pháp

Vốn điều lệ: 2 tỷ VND (GCNĐKDN số 0111319828 — TP Hà Nội, 19/12/2025)

Nguồn doanh thu hợp pháp:
  ├── Phí giao dịch Spot CEX (maker/taker fee)
  ├── Phí giao dịch P2P (escrow commission)
  ├── Phí giao dịch Futures
  ├── Phí niêm yết ICO/ITO (Mẫu 01 — bản cáo bạch)
  ├── Phí NFT Marketplace (royalty + listing)
  └── Phí dịch vụ Staking / Lending Pool

Quản lý dòng tiền:
  └── 100% giao dịch VND qua tài khoản ngân hàng chuyên dùng
      → Ngân hàng đối tác được NHNN cấp phép
      → Kết nối NAPAS/IBFT — minh bạch, kiểm soát được

1.3 Vai trò hệ thống Smart Contract

Vai trò Chức năng cụ thể
Quản trị token GIV Cơ chế mở khóa theo volume giao dịch thực tế
Cổng VNL — stablecoin VND Định danh dòng tiền nạp/rút, kết nối ngân hàng
Kiểm soát nhà đầu tư Whitelist KYC on-chain theo Điều 6/7 NQ-05
Ngắt khẩn cấp Circuit breaker theo yêu cầu Bộ Tài chính
Bằng chứng pháp lý Events on-chain bất biến — kiểm toán độc lập

II. Kiến trúc Smart Contract

Sơ đồ tổng thể

╔═══════════════════════════════════════════════════════════════════╗
║  NHÀ ĐẦU TƯ (đã KYC/eKYC — Điều 6/7 NQ-05)                      ║
║  Tài khoản ngân hàng thương mại trong nước                        ║
╚══════════════════════════╤════════════════════════════════════════╝
                           │ [Nạp tiền VND → NAPAS/IBFT]
                           ▼
╔═══════════════════════════════════════════════════════════════════╗
║  TẦNG 1: KYC/AML — InvestorWhitelist (on-chain)                   ║
║  • Đồng bộ từ DB: kycApplication.status = APPROVED               ║
║  • Phân loại: DOMESTIC / FOREIGN (Điều 6/7 NQ-05)               ║
║  • AML status: CLEAR / FLAGGED / REVIEW_REQUIRED                 ║
║  • Tái xác thực: 365 ngày                                         ║
╚══════════════════════════╤════════════════════════════════════════╝
                           │ [isEligible() = true]
                           ▼
╔═══════════════════════════════════════════════════════════════════╗
║  TẦNG 2: VNLToken — Stablecoin 1:1 VND                           ║
║  • Mint khi ngân hàng xác nhận nạp tiền thành công               ║
║  • AML quota: giới hạn theo hạn mức phê duyệt                    ║
║  • Burn khi rút tiền về ngân hàng                                 ║
║  • Tuân thủ Điều 15 NQ-05: tách biệt quỹ KH / quỹ sàn           ║
╚══════════════════════════╤════════════════════════════════════════╝
                           │ [VNL giao dịch trên sàn]
                           ▼
╔═══════════════════════════════════════════════════════════════════╗
║  TẦNG 3: Order Matching Engine (CEX/DEX/P2P)                     ║
║  • assertTradingAllowed() — EmergencyCircuitBreaker               ║
║  • GIVToken.unlockTokens() — Mở khóa GIV theo volume             ║
║  • triggerTaxOnTransaction() — Thuế Luật 71/2025/QH15            ║
╚══════════════════════════╤════════════════════════════════════════╝
                           │ [Events bất biến on-chain]
                           ▼
                 ┌──────────────────────┐
                 │  BSCScan Explorer    │
                 │  bscscan.com/tx/...  │
                 │  Thanh tra Bộ TC     │
                 │  tra cứu bất kỳ lúc │
                 └──────────────────────┘

III. CONTRACT 1: GIVToken

File: contracts/GIVToken.sol Vai trò: Token quản trị nội bộ — mở khóa theo volume giao dịch thực tế (hệ số α)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title GIVToken
 * @notice Token quản trị GVI Network — mở khóa theo volume giao dịch VNL
 * @dev Tuân thủ NQ-05/2025/NQ-CP: không phải chứng khoán, không phải tiền pháp định
 *      Hệ số α được quản trị bởi givUnlockConfig trong DB (off-chain governance)
 */
contract GIVToken {
    string  public constant name     = "GoldVN Invest Token";
    string  public constant symbol   = "GIV";
    uint8   public constant decimals = 18;

    uint256 public totalSupply;
    address public owner;
    address public escrowEngine;   // Backend GVI được ủy quyền

    mapping(address => uint256) public balanceOf;
    mapping(address => uint256) public lockedBalance;
    mapping(address => mapping(address => uint256)) public allowance;

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
    event TokensLocked(address indexed account, uint256 amount, string reason);
    event TokensUnlocked(address indexed account, uint256 amount);
    event EscrowEngineSet(address indexed engine);

    modifier onlyOwner()  { require(msg.sender == owner,        "GIV: not owner");  _; }
    modifier onlyEscrow() { require(msg.sender == escrowEngine, "GIV: not escrow"); _; }

    constructor(uint256 initialSupply) {
        owner                 = msg.sender;
        totalSupply           = initialSupply * 10**18;
        balanceOf[msg.sender] = totalSupply;
        emit Transfer(address(0), msg.sender, totalSupply);
    }

    function setEscrowEngine(address engine) external onlyOwner {
        require(engine != address(0), "GIV: zero address");
        escrowEngine = engine;
        emit EscrowEngineSet(engine);
    }

    /// @notice Khóa GIV theo lịch vesting — gọi khi phát hành ICO/ITO
    function lockTokens(address account, uint256 amount, string calldata reason)
        external onlyOwner
    {
        require(balanceOf[account] >= amount, "GIV: insufficient balance");
        balanceOf[account]     -= amount;
        lockedBalance[account] += amount;
        emit TokensLocked(account, amount, reason);
    }

    /// @notice Mở khóa GIV — gọi từ backend sau khi volume giao dịch đủ điều kiện
    function unlockTokens(address account, uint256 amount) external onlyEscrow {
        require(lockedBalance[account] >= amount, "GIV: insufficient locked");
        lockedBalance[account] -= amount;
        balanceOf[account]     += amount;
        emit TokensUnlocked(account, amount);
    }

    function transfer(address to, uint256 amount) external returns (bool) {
        require(balanceOf[msg.sender] >= amount, "GIV: insufficient balance");
        balanceOf[msg.sender] -= amount;
        balanceOf[to]         += amount;
        emit Transfer(msg.sender, to, amount);
        return true;
    }

    function approve(address spender, uint256 amount) external returns (bool) {
        allowance[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }

    function transferFrom(address from, address to, uint256 amount) external returns (bool) {
        require(balanceOf[from]             >= amount, "GIV: insufficient balance");
        require(allowance[from][msg.sender] >= amount, "GIV: insufficient allowance");
        allowance[from][msg.sender] -= amount;
        balanceOf[from]             -= amount;
        balanceOf[to]               += amount;
        emit Transfer(from, to, amount);
        return true;
    }
}

IV. CONTRACT 2: VNLToken

File: contracts/VNLToken.sol Vai trò: Stablecoin 1:1 VND — cổng xác định dòng tiền nạp/rút

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title VNLToken
 * @notice Stablecoin nội bộ 1 VNL = 1 VND — cổng kết nối hệ thống ngân hàng
 * @dev Tuân thủ Điều 15 NQ-05: mint chỉ khi ngân hàng xác nhận nạp tiền thành công
 *      AML quota theo quy định NHNN và Luật PCRT
 */
contract VNLToken {
    string  public constant name     = "VNL Token";
    string  public constant symbol   = "VNL";
    uint8   public constant decimals = 0;   // 1 VNL = 1 VND

    uint256 public totalSupply;
    address public owner;        // GVI Admin (Multisig)
    address public escrowEngine; // Backend oracle được ủy quyền

    mapping(address => uint256) public balanceOf;
    mapping(address => bool)    public isFrozen;       // AML freeze
    mapping(address => uint256) public approvedQuota;  // Hạn mức AML

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event VNLMinted(address indexed to, uint256 amount, string bankRef);
    event VNLBurned(address indexed from, uint256 amount);
    event AccountFrozen(address indexed account, bool status);
    event QuotaSet(address indexed account, uint256 quota);

    modifier onlyOwner()  { require(msg.sender == owner,        "VNL: not owner");  _; }
    modifier onlyEscrow() { require(msg.sender == escrowEngine, "VNL: not escrow"); _; }
    modifier notFrozen(address a) {
        require(!isFrozen[a], "VNL: account frozen — AML compliance");
        _;
    }

    constructor() { owner = msg.sender; }

    function setEscrowEngine(address engine) external onlyOwner {
        require(engine != address(0), "VNL: zero address");
        escrowEngine = engine;
    }

    /// @notice Phong tỏa/mở băng tài khoản vi phạm AML
    function freezeAccount(address account, bool status) external onlyOwner {
        isFrozen[account] = status;
        emit AccountFrozen(account, status);
    }

    /// @notice Cấp hạn mức giao dịch theo quy định AML (0 = không giới hạn)
    function setQuota(address account, uint256 quota) external onlyOwner {
        approvedQuota[account] = quota;
        emit QuotaSet(account, quota);
    }

    /// @notice Mint VNL khi ngân hàng xác nhận nạp tiền thành công
    ///         bankRef = mã tham chiếu giao dịch ngân hàng (NAPAS/IBFT ref)
    function mintForDeposit(
        address to,
        uint256 amount,
        string calldata bankRef
    ) external onlyEscrow notFrozen(to) {
        require(
            approvedQuota[to] == 0 || amount <= approvedQuota[to],
            "VNL: exceeds approved quota"
        );
        totalSupply   += amount;
        balanceOf[to] += amount;
        emit Transfer(address(0), to, amount);
        emit VNLMinted(to, amount, bankRef);
    }

    /// @notice Burn VNL khi nhà đầu tư rút tiền về ngân hàng
    function burnForWithdraw(uint256 amount) external notFrozen(msg.sender) {
        require(balanceOf[msg.sender] >= amount, "VNL: insufficient balance");
        balanceOf[msg.sender] -= amount;
        totalSupply           -= amount;
        emit Transfer(msg.sender, address(0), amount);
        emit VNLBurned(msg.sender, amount);
    }

    function transfer(address to, uint256 amount)
        external notFrozen(msg.sender) notFrozen(to) returns (bool)
    {
        require(balanceOf[msg.sender] >= amount, "VNL: insufficient balance");
        balanceOf[msg.sender] -= amount;
        balanceOf[to]         += amount;
        emit Transfer(msg.sender, to, amount);
        return true;
    }
}

V. CONTRACT 3: GIVGovernance

File: contracts/GIVGovernance.sol Vai trò: dPoS oracle định giá GIV — biên độ ±7% ngăn thao túng giá

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title GIVGovernance
 * @notice Cơ chế quản trị định giá GIV — weighted-average từ mạng Validator
 * @dev Mỗi Validator vote 1 lần/24h; biên độ ±7% chống thao túng
 *      Kết quả đồng bộ vào DB qua givGovernanceService.ts
 */
contract GIVGovernance {
    address public admin;
    uint256 public currentGIVPrice;
    uint256 public constant MAX_DEVIATION = 7;  // ±7%
    uint256 public minShare;

    struct Validator {
        uint256 shares;
        bool    isActive;
        uint256 lastVotedPrice;
        uint256 lastVoteAt;
    }

    mapping(address => Validator) public validators;
    address[] public validatorList;

    event PriceVoted(address indexed validator, uint256 price, uint256 timestamp);
    event PriceAggregated(uint256 newPrice, uint256 voterCount, uint256 timestamp);
    event ValidatorUpdated(address indexed validator, uint256 shares, bool active);

    modifier onlyAdmin() { require(msg.sender == admin, "GIVGov: not admin"); _; }

    constructor(uint256 _minShare, uint256 _initialPrice) {
        admin           = msg.sender;
        minShare        = _minShare;
        currentGIVPrice = _initialPrice;
    }

    /// @notice Validator vote giá GIV (1 lần/24h, trong biên độ ±7%)
    /// @param proposedPrice Giá GIV × 100 (VD: 25000 = 250.00 VND/GIV)
    function submitGIVPrice(uint256 proposedPrice) external {
        Validator storage v = validators[msg.sender];
        require(v.isActive, "GIVGov: not active validator");
        require(block.timestamp >= v.lastVoteAt + 1 days, "GIVGov: one vote per 24h");

        if (currentGIVPrice > 0) {
            uint256 maxP = currentGIVPrice * (100 + MAX_DEVIATION) / 100;
            uint256 minP = currentGIVPrice * (100 - MAX_DEVIATION) / 100;
            require(proposedPrice >= minP && proposedPrice <= maxP,
                "GIVGov: price outside 7% boundary");
        }

        v.lastVotedPrice = proposedPrice;
        v.lastVoteAt     = block.timestamp;
        emit PriceVoted(msg.sender, proposedPrice, block.timestamp);
    }

    /// @notice Tổng hợp weighted-average — ai cũng có thể gọi
    function aggregateGIVPrice() external {
        uint256 weightedSum = 0;
        uint256 totalShares = 0;
        uint256 voteCount   = 0;

        for (uint256 i = 0; i < validatorList.length; i++) {
            Validator memory v = validators[validatorList[i]];
            if (v.isActive && block.timestamp - v.lastVoteAt <= 1 days && v.lastVotedPrice > 0) {
                weightedSum += v.lastVotedPrice * v.shares;
                totalShares += v.shares;
                voteCount++;
            }
        }

        require(totalShares > 0, "GIVGov: no active votes in last 24h");
        currentGIVPrice = weightedSum / totalShares;
        emit PriceAggregated(currentGIVPrice, voteCount, block.timestamp);
    }

    function updateValidator(address valAddr, uint256 shares) external onlyAdmin {
        bool wasActive = validators[valAddr].isActive;
        bool nowActive = shares >= minShare;
        validators[valAddr].shares   = shares;
        validators[valAddr].isActive = nowActive;
        if (nowActive && !wasActive) validatorList.push(valAddr);
        emit ValidatorUpdated(valAddr, shares, nowActive);
    }
}

VI. CONTRACT 4: EmergencyCircuitBreaker

File: contracts/EmergencyCircuitBreaker.sol Vai trò: Cơ chế ngắt khẩn cấp — yêu cầu bắt buộc trong thí điểm 5 năm NQ-05

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";

/**
 * @title EmergencyCircuitBreaker
 * @notice Cơ chế ngắt khẩn cấp theo yêu cầu Điều kiện thí điểm NQ-05/2025/NQ-CP
 * @dev REGULATOR_ROLE = Bộ Tài chính / cơ quan quản lý
 *      OPERATOR_ROLE  = Hệ thống tự động GVI (backend)
 */
contract EmergencyCircuitBreaker is AccessControl, Pausable {

    bytes32 public constant REGULATOR_ROLE = keccak256("REGULATOR_ROLE");
    bytes32 public constant OPERATOR_ROLE  = keccak256("OPERATOR_ROLE");

    mapping(address => bool) private _tokenPaused;

    event GlobalPaused  (address indexed by, uint256 timestamp, string reason);
    event GlobalUnpaused(address indexed by, uint256 timestamp);
    event TokenPaused   (address indexed token, address indexed by, uint256 timestamp, string reason);
    event TokenUnpaused (address indexed token, address indexed by, uint256 timestamp);

    constructor(address admin, address regulator) {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(REGULATOR_ROLE,     regulator);
        _grantRole(OPERATOR_ROLE,      admin);
    }

    modifier tradingAllowed(address token) {
        require(!paused(),             "ECB: Platform globally paused");
        require(!_tokenPaused[token],  "ECB: Token trading suspended");
        _;
    }

    function pauseAll(string calldata reason) external onlyRole(REGULATOR_ROLE) {
        _pause();
        emit GlobalPaused(msg.sender, block.timestamp, reason);
    }

    function unpauseAll() external onlyRole(REGULATOR_ROLE) {
        _unpause();
        emit GlobalUnpaused(msg.sender, block.timestamp);
    }

    function pauseToken(address token, string calldata reason) external {
        require(hasRole(REGULATOR_ROLE, msg.sender) || hasRole(OPERATOR_ROLE, msg.sender),
            "ECB: lacks permission");
        _tokenPaused[token] = true;
        emit TokenPaused(token, msg.sender, block.timestamp, reason);
    }

    function unpauseToken(address token) external {
        require(hasRole(REGULATOR_ROLE, msg.sender) || hasRole(OPERATOR_ROLE, msg.sender),
            "ECB: lacks permission");
        _tokenPaused[token] = false;
        emit TokenUnpaused(token, msg.sender, block.timestamp);
    }

    function isTokenPaused(address token) external view returns (bool) {
        return paused() || _tokenPaused[token];
    }
}

VII. CONTRACT 5: InvestorWhitelist

File: contracts/InvestorWhitelist.sol Vai trò: Kiểm soát nhà đầu tư on-chain theo Điều 6/7 NQ-05/2025/NQ-CP

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/access/AccessControl.sol";

/**
 * @title InvestorWhitelist
 * @notice Whitelist KYC on-chain — Điều 6/7 NQ-05/2025/NQ-CP
 * @dev Đồng bộ từ DB: kycApplication.status = "APPROVED" → approveInvestor()
 *      KYC_OPERATOR = Backend GVI (gọi sau khi eKYC pass)
 *      REGULATOR_ROLE = có thể revoke hàng loạt khi phát sinh vi phạm
 */
contract InvestorWhitelist is AccessControl {

    bytes32 public constant KYC_OPERATOR   = keccak256("KYC_OPERATOR");
    bytes32 public constant REGULATOR_ROLE = keccak256("REGULATOR_ROLE");

    enum InvestorType { NONE, DOMESTIC, FOREIGN }

    struct Investor {
        bool         isWhitelisted;
        InvestorType investorType;
        uint8        kycLevel;     // 1 | 2 | 3
        uint8        amlStatus;    // 0=CLEAR, 1=FLAGGED, 2=REVIEW_REQUIRED
        uint256      approvedAt;
        uint256      expiresAt;    // Tái xác thực định kỳ
        string       userId;       // Off-chain DB UUID
    }

    mapping(address => Investor) private _investors;

    event InvestorApproved(address indexed wallet, InvestorType investorType,
        uint8 kycLevel, string userId, uint256 expiresAt);
    event InvestorRevoked(address indexed wallet, address indexed by, string reason);
    event InvestorAmlFlagged(address indexed wallet, uint8 newAmlStatus);

    uint256 public constant DEFAULT_VALIDITY = 365 days;

    constructor(address admin) {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(KYC_OPERATOR,       admin);
    }

    function approveInvestor(
        address      wallet,
        InvestorType investorType,
        uint8        kycLevel,
        string calldata userId,
        uint256      validitySeconds
    ) external onlyRole(KYC_OPERATOR) {
        require(wallet != address(0),                "IW: zero address");
        require(investorType != InvestorType.NONE,   "IW: invalid type");
        require(kycLevel >= 1 && kycLevel <= 3,      "IW: kycLevel 1-3");

        uint256 validity  = validitySeconds > 0 ? validitySeconds : DEFAULT_VALIDITY;
        uint256 expiresAt = block.timestamp + validity;

        _investors[wallet] = Investor({
            isWhitelisted: true,
            investorType:  investorType,
            kycLevel:      kycLevel,
            amlStatus:     0,
            approvedAt:    block.timestamp,
            expiresAt:     expiresAt,
            userId:        userId
        });

        emit InvestorApproved(wallet, investorType, kycLevel, userId, expiresAt);
    }

    function revokeInvestor(address wallet, string calldata reason) external {
        require(hasRole(KYC_OPERATOR, msg.sender) || hasRole(REGULATOR_ROLE, msg.sender),
            "IW: lacks revoke permission");
        _investors[wallet].isWhitelisted = false;
        emit InvestorRevoked(wallet, msg.sender, reason);
    }

    function updateAmlStatus(address wallet, uint8 amlStatus)
        external onlyRole(KYC_OPERATOR)
    {
        require(amlStatus <= 2, "IW: invalid AML status");
        _investors[wallet].amlStatus = amlStatus;
        emit InvestorAmlFlagged(wallet, amlStatus);
    }

    function isEligible(address wallet) external view returns (bool) {
        Investor memory inv = _investors[wallet];
        return inv.isWhitelisted
            && block.timestamp < inv.expiresAt
            && inv.amlStatus == 0;
    }

    function getInvestor(address wallet) external view returns (Investor memory) {
        return _investors[wallet];
    }
}

VIII. Luồng vận hành thực tế

8.1 Nhà đầu tư nạp tiền VND

[Nhà đầu tư] → Chuyển khoản VND vào TK ngân hàng chuyên dùng GVI
                      ↓
              [Webhook NAPAS/IBFT → Backend GVI]
                      ↓
              [Oracle xác nhận → VNLToken.mintForDeposit(user, amount, bankRef)]
                      ↓
              [VNL credited → ví FIAT của user trong DB]
                      ↓
              Event: VNLMinted(user, amount, bankRef) ← on-chain evidence

8.2 Nhà đầu tư thực hiện giao dịch

[Nhà đầu tư] → Đặt lệnh mua/bán
                      ↓
              [assertTradingAllowed(symbol)] ← CircuitBreaker check
                      ↓
              [InvestorWhitelist.isEligible(wallet)] ← KYC check
                      ↓
              [Order Matching Engine khớp lệnh]
                      ↓
              [triggerTaxOnTransaction()] ← Thuế tự động Luật 71
              [triggerGivUnlockOnTrade()] ← Mở khóa GIV theo volume
              [walletAuditLog] ← Nhật ký bất biến

8.3 Nhà đầu tư rút tiền VND

[Nhà đầu tư] → Yêu cầu rút tiền
                      ↓
              [KYC Level ≥ 2 required]
                      ↓
              [AML check: transactionMonitoring]
                      ↓
              [VNLToken.burnForWithdraw(amount)] ← Giảm total supply
                      ↓
              [Chuyển khoản VND từ TK chuyên dùng → TK ngân hàng NĐT]
                      ↓
              Event: VNLBurned(user, amount) ← on-chain evidence

IX. On-chain Legal Evidence

Event Contract Ý nghĩa pháp lý
VNLMinted(to, amount, bankRef) VNLToken Chứng từ nạp tiền — liên kết giao dịch ngân hàng
VNLBurned(from, amount) VNLToken Chứng từ rút tiền
TokensLocked(account, amount, reason) GIVToken Phong tỏa GIV theo lịch vesting
TokensUnlocked(account, amount) GIVToken Giải phóng GIV sau khi đủ điều kiện
PriceAggregated(price, count, ts) GIVGovernance Biên bản xác định giá GIV — có chữ ký validator
InvestorApproved(wallet, type, level) InvestorWhitelist Phê duyệt KYC on-chain
InvestorRevoked(wallet, by, reason) InvestorWhitelist Thu hồi quyền giao dịch
AccountFrozen(account, status) VNLToken Lệnh AML — on-chain timestamp
GlobalPaused(by, ts, reason) CircuitBreaker Ngắt khẩn cấp toàn sàn
TokenPaused(token, by, ts, reason) CircuitBreaker Tạm dừng giao dịch từng token

Tra cứu: https://bscscan.com/tx/[hash]


X. Checklist trước khi lên BSC Mainnet

Kỹ thuật

Nghiệp vụ & Pháp lý

Bảo mật (BẮT BUỘC)

Cấu hình .env sau khi deploy

# BSC Smart Contracts — GVI Network
GIV_CONTRACT_BSC=0x_______________
VNL_TOKEN_CONTRACT_BSC=0x_______________
GIV_GOV_CONTRACT_BSC=0x_______________
CIRCUIT_BREAKER_CONTRACT=0x_______________
INVESTOR_WHITELIST_CONTRACT=0x_______________

# Backend config
CIRCUIT_BREAKER_SIGNER_KEY=0x_______________  # OPERATOR_ROLE private key
GIV_UNLOCK_ALPHA=0.0005                        # 0.05% per VNL volume
MAX_CONCURRENT_SESSIONS=5

XI. Tài liệu tham chiếu

Tài liệu Đường dẫn
Kiến trúc hệ thống đầy đủ docs/newproject001.md
Đề án kỹ thuật chi tiết docs/GVI-NETWORK-TECHNICAL-PROPOSAL.md
GVI contracts source backend/ecosystem/smart-contracts/gvi/
Tax Engine backend/src/tax/taxCalculatorEngine.ts
Circuit Breaker Service backend/src/security/circuitBreakerService.ts
Session Guard backend/src/security/sessionGuard.ts
Migration SQL backend/scripts/migration-tax-circuit-breaker.sql
BSCScan Mainnet https://bscscan.com
BSCScan Testnet https://testnet.bscscan.com
Remix IDE https://remix.ethereum.org
Gnosis Safe https://safe.global

Tài liệu kỹ thuật nội bộ v3.0.0 — GoldVN Invest (GVI Network) GCNĐKDN số 0111319828 — Phòng ĐKKD & TCDN Hà Nội cấp ngày 19/12/2025 Mọi thay đổi phải được phê duyệt bởi Ban Quản Trị GVI và lưu vào git commit có GPG signature.