# usdcx-token

{% code title=".usdcx" lineNumbers="true" expandable="true" %}

```clarity
;; USDCx 代币
;;
;; 本合约为可替代合约实现了 SIP-010 特性。
;;
;; 本合约采用基于角色的访问控制系统来管理协议权限。
;; 共有三种角色：
;;
;; - `governance`：允许更新协议合约并添加/移除角色
;; - `mint`：允许铸造和销毁代币
;; - `pause`：允许暂停和取消暂停协议
;;

(impl-trait 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait)

;; `tx-sender` 或 `contract-caller` 试图移动它不拥有的代币。
(define-constant ERR_NOT_OWNER (err u4))
;; `contract-caller` 试图使用其未被授权使用的函数。
(define-constant ERR_UNAUTHORIZED (err u400))
;; 协议已暂停。
(define-constant ERR_PAUSED (err u401))

(define-fungible-token usdcx-token)

(define-data-var token-name (string-ascii 32) "USDCx")
(define-data-var token-symbol (string-ascii 10) "USDCx")
;; 代币元数据的 SIP-16 URI
(define-data-var token-uri (optional (string-utf8 256)) (some u"https://ipfs.io/ipfs/bafkreifkhq47bgrlq2z2qgtps65eawgp6xsqkwldz57y2bjpefgo5zvza4"))
(define-constant token-decimals u6)

;; 允许更新协议合约
(define-constant governance-role 0x00)
;; 允许铸造和销毁代币
(define-constant mint-role 0x01)
;; 允许暂停和取消暂停协议
(define-constant pause-role 0x02)

;; 允许协议被暂停
(define-data-var paused bool false)

;; 活跃协议合约的映射（按角色）
(define-map active-protocol-contracts
  {
    caller: principal,
    role: (buff 1),
  }
  bool
)

;; 合约 .usdcx-v1 会自动拥有 `mint` 角色
(map-set active-protocol-contracts {
  caller: .usdcx-v1,
  role: mint-role,
}
  true
)
;; 默认将合约部署者设为拥有 `governance` 角色
(map-set active-protocol-contracts {
  caller: tx-sender,
  role: governance-role,
}
  true
)

;; SIP-010 函数

(define-public (transfer
    (amount uint)
    (sender principal)
    (recipient principal)
    (memo (optional (buff 34)))
  )
  (begin
    (asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender))
      ERR_NOT_OWNER
    )
    (try! (ft-transfer? usdcx-token amount sender recipient))
    (match memo
      to-print (print to-print)
      0x
    )
    (ok true)
  )
)

(define-read-only (get-name)
  (ok (var-get token-name))
)

(define-read-only (get-symbol)
  (ok (var-get token-symbol))
)

(define-read-only (get-decimals)
  (ok token-decimals)
)

(define-read-only (get-balance (who principal))
  (ok (ft-get-balance usdcx-token who))
)

(define-read-only (get-balance-available (who principal))
  (ok (ft-get-balance usdcx-token who))
)

(define-read-only (get-balance-locked (who principal))
  (ok (ft-get-balance usdcx-token who))
)

(define-read-only (get-total-supply)
  (ok (ft-get-supply usdcx-token))
)

(define-read-only (get-token-uri)
  (ok (var-get token-uri))
)

;; 协议调用者验证

;; 检查 contract-caller 是否为协议合约
(define-read-only (is-protocol-caller
    (contract-flag (buff 1))
    (contract principal)
  )
  (validate-protocol-caller contract-flag contract)
)

;; 验证给定的 principal 是否为协议合约
(define-read-only (validate-protocol-caller
    (contract-flag (buff 1))
    (contract principal)
  )
  (begin
    ;; 检查调用者是否拥有所需角色
    (asserts!
      (default-to false
        (map-get? active-protocol-contracts {
          caller: contract,
          role: contract-flag,
        })
      )
      ERR_UNAUTHORIZED
    )
    (ok true)
  )
)

;; 协议暂停

(define-read-only (is-protocol-paused)
  (var-get paused)
)

;; 验证协议未处于暂停状态
(define-read-only (validate-protocol-active)
  (ok (asserts! (not (is-protocol-paused)) ERR_PAUSED))
)

;; --- 协议函数

;; 将代币从一个账户转移到另一个账户。
;; 只有 `mint` 角色允许调用此函数。
(define-public (protocol-transfer
    (amount uint)
    (sender principal)
    (recipient principal)
  )
  (begin
    ;; #[filter(amount, sender, recipient)]
    (try! (validate-protocol-active))
    (try! (validate-protocol-caller mint-role contract-caller))
    (ft-transfer? usdcx-token amount sender recipient)
  )
)

;; 向账户铸造代币。
;; 只有 `mint` 角色允许调用此函数。
(define-public (protocol-mint
    (amount uint)
    (recipient principal)
  )
  (begin
    ;; #[filter(amount, recipient)]
    (try! (validate-protocol-active))
    (try! (validate-protocol-caller mint-role contract-caller))
    (ft-mint? usdcx-token amount recipient)
  )
)

;; 从账户销毁代币。
;; 只有 `mint` 角色允许调用此函数。
(define-public (protocol-burn
    (amount uint)
    (owner principal)
  )
  (begin
    ;; #[filter(amount, owner)]
    (try! (validate-protocol-active))
    (try! (validate-protocol-caller mint-role contract-caller))
    (ft-burn? usdcx-token amount owner)
  )
)

;; 设置代币名称。
;; 只有 `governance` 角色允许调用此函数。
(define-public (protocol-set-name (new-name (string-ascii 32)))
  (begin
    ;; #[filter(new-name)]
    (try! (validate-protocol-active))
    (try! (validate-protocol-caller governance-role contract-caller))
    (ok (var-set token-name new-name))
  )
)

;; 设置代币符号。
;; 只有 `governance` 角色允许调用此函数。
(define-public (protocol-set-symbol (new-symbol (string-ascii 10)))
  (begin
    ;; #[filter(new-symbol)]
    (try! (validate-protocol-active))
    (try! (validate-protocol-caller governance-role contract-caller))
    (ok (var-set token-symbol new-symbol))
  )
)

;; 设置代币元数据的 SIP-16 URI。
;; 只有 `governance` 角色允许调用此函数。
(define-public (protocol-set-token-uri (new-uri (optional (string-utf8 256))))
  (begin
    ;; #[filter(new-uri)]
    (try! (validate-protocol-active))
    (try! (validate-protocol-caller governance-role contract-caller))
    (ok (var-set token-uri new-uri))
  )
)

;; 用于向多个收款人铸造代币的辅助函数。
;; 只有 `mint` 角色允许调用此函数。
(define-private (protocol-mint-many-iter (item {
  amount: uint,
  recipient: principal,
}))
  ;; #[allow(unchecked_data)]
  (ft-mint? usdcx-token (get amount item) (get recipient item))
)

;; 向多个收款人铸造代币。
;; 只有 `mint` 角色允许调用此函数。
(define-public (protocol-mint-many (recipients (list 200 {
  amount: uint,
  recipient: principal,
})))
  (begin
    ;; #[filter(recipients)]
    (try! (validate-protocol-active))
    (try! (validate-protocol-caller mint-role contract-caller))
    (ok (map protocol-mint-many-iter recipients))
  )
)

;; 设置一个活跃的协议调用者。
;; 只有 `governance` 角色允许调用此函数。
(define-public (set-active-protocol-caller
    (caller principal)
    (role (buff 1))
    (enabled bool)
  )
  (begin
    ;; #[filter(caller, role, enabled)]
    (try! (validate-protocol-active))
    (try! (validate-protocol-caller governance-role contract-caller))
    (map-set active-protocol-contracts {
      caller: caller,
      role: role,
    }
      enabled
    )
    (ok true)
  )
)

;; 暂停协议。
;; 只有 `pause` 角色允许调用此函数。
(define-public (pause)
  (begin
    (try! (validate-protocol-caller pause-role contract-caller))
    (print {
      topic: "pause",
      paused: true,
      caller: contract-caller,
    })
    (ok (var-set paused true))
  )
)

;; 取消暂停协议。
;; 只有 `pause` 角色允许调用此函数。
(define-public (unpause)
  (begin
    (try! (validate-protocol-caller pause-role contract-caller))
    (print {
      topic: "pause",
      paused: false,
      caller: contract-caller,
    })
    (ok (var-set paused false))
  )
)

```

{% endcode %}

## **USDCx-Token 合约摘要**

本合约实现 **USDCx**，这是一个位于 Stacks 上的 SIP-010 可替代代币，具有 **基于角色的访问控制系统** 和 **暂停功能** 用于协议安全。它暴露了用于转移、供应查询和元数据的标准 SIP-010 接口，同时提供仅供协议使用的铸造、销毁、治理更新和暂停功能。

#### **角色**

该合约定义了三种特权角色：

* **治理（`governance-role`)** ）——管理协议配置、更新代币元数据并分配角色。
* **铸造（`mint-role`)** ）——授权铸造、销毁并执行协议级转账。
* **暂停（`pause-role`)** ）——授权暂停和取消暂停协议。

协议暂停会出于安全原因停止状态变更操作。合约部署者会自动获得 **治理** 角色。配套合约 `.usdcx-v1` 会自动获得 **铸造** 角色。

***

### 逐函数解析

### **SIP-010 标准函数**

#### **`transfer(amount, sender, recipient, memo)`**

按照 SIP-010 规则，在主体之间转移 USDCx。该函数检查发送方是否为 `tx-sender` 或 `contract-caller` （用于管理托管或金库的合约），然后执行转移。可选的 memo 会记录在链上。

#### **`get-name()`**, **`get-symbol()`**, **`get-decimals()`**

标准的 SIP-010 元数据获取函数，返回代币名称、符号和小数精度。

#### **`get-balance(who)`**, **`get-balance-available(who)`**, **`get-balance-locked(who)`**

返回给定主体的代币余额。在此实现中，三个访问器函数都返回相同的 SIP-010 余额值。

#### **`get-total-supply()`**

返回铸造减去销毁后的 USDCx 总供应量。

#### **`get-token-uri()`**

返回代币元数据 URI。

***

### **协议调用者验证**

这些函数强制执行合约的基于角色的权限。

#### **`is-protocol-caller(role, contract)`**

检查指定的合约主体是否拥有所需角色。

#### **`validate-protocol-caller(role, contract)`**

确保调用者拥有正确角色。否则，返回 `ERR_UNAUTHORIZED`.

#### **`is-protocol-paused()`**

返回协议当前是否已暂停。

#### **`validate-protocol-active()`**

断言协议未暂停，否则返回 `ERR_PAUSED`.

***

### **仅限协议的代币操作**

这些函数仅允许已授权的协议合约进行铸造/销毁/转移。

#### **`protocol-transfer(amount, sender, recipient)`**

代表另一个合约执行协议级转账。只有具有 **铸造角色** 的调用者才能使用它。如果协议已暂停，则失败。

#### **`protocol-mint(amount, recipient)`**

向某个主体铸造新的 USDCx。仅限于 **铸造角色** 并且在暂停时会被禁用。

#### **`protocol-burn(amount, owner)`**

从某个主体的余额中销毁代币。也仅限于 **铸造角色** 并且在暂停时会被禁用。

#### **`protocol-mint-many(recipients)`**

批量向多个收款人一次性铸造代币。每个项目包含 `{ amount, recipient }`。仅可由拥有 **铸造角色**.

***

### **治理函数**

只有 **治理角色** 可以调用这些函数。

#### **`protocol-set-name(new-name)`**

更新代币的 SIP-010 名称。

#### **`protocol-set-symbol(new-symbol)`**

更新代币的 SIP-010 交易代码符号。

#### **`protocol-set-token-uri(new-uri)`**

更新 SIP-016 元数据 URI。

#### **`set-active-protocol-caller(caller, role, enabled)`**

向特定协议角色中添加或移除某个主体。\
用于轮换系统、更新配套合约或委派新职责。

***

### **暂停控制**

这些函数允许协议为安全或维护而停止运行。

#### **`pause()`**

暂停合约，禁用铸造、销毁以及所有仅限协议的操作。仅可由 **暂停角色**.

#### **`unpause()`**

在暂停后重新启用协议。也仅限于 **暂停角色**.

这两个函数都会发出链上事件以提高透明度。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.stacks.co/learn/zh/bridging/usdcx/contracts/usdcx-token.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
