# MRC-20

{% hint style="warning" %}
請注意該協議仍在測試網測試中,我們會在充分測試後在比特幣主網合適的區塊高度啟動該協議
{% endhint %}

MRC-20 是基於 MetaID 的一個 Fungible Token 發行協議，使用者可以透過 MRC-20 協議發行資產並制定鑄造方式。與其他資產發行協議相比，MRC-20 協議最大的特點是其發行方式能夠與各人鏈數據以及 MetaID 協議緊密結合，從而能夠滿足各種鏈上活動的資產發行方式。簡單來說，MRC-20 是一種為滿足日後各種 Web3 活動而制定的 Fungible Token 發行協議。

## 協議格式

### 部署

#### PIN路徑：`/ft/mrc20/deploy`

後端索引器應只對符合路徑的 PIN做驗證和索引

該路徑下的 PIN 不接受 modify 和 revoke操作

#### 協議格式：

```jsx
{
  "tick": "satoshi", // 2-24 字符
  "amtPerMint": "1000", // 每次鑄造獲得的總代幣數量 [1, 1e12]
  "mintCount": "100", // 最大允許鑄造次數 [1, 1e12]
  "tokenName": "SatoshiTheLegend", // 選填，代幣全名，0-48 字符
  "decimals": "8", // 選填，小數位數 0 至 12，默認為 8  
  "premineCount": "60", // 選填，部署時預先鑄造的次數，默認為 0，[0, mintCount]
  "beginHeight": "851235", // 選填，鑄造事件開始的區塊高度
  "endHeight": "851781", // 選填，鑄造事件結束的區塊高度
  "metadata": "Arbitrary Data", // 選填，可以包含額外資料如代幣描述、圖示等，無格式要求
  "payCheck": { // 選填，檢查付款以驗證鑄造資格
    "payTo": "address", // 檢查輸出是否匹配指定地址
    "payAmount": "" // 以 satoshi 為單位，檢查是否支付了指定數量的 satoshi
  },
  "pinCheck": { // 選填，檢查 PIN 以驗證鑄造資格
    "creator": "", // 創建 PIN 的人，使用完整的 MetaID
    "path": "/", // PIN 的路徑
    "count": "1", // 0~n，所需的 PIN 數量
    "lvl": "6" // PIN 的最低等級
  }
}
```

#### 要點說明：

• 合法的創始交易後，該 `tick` 將被分配一個唯一的 id，該 id 用於標識該 MRC-20 代幣。該 id 用 pinid 表示

• `tick` 為全局唯一，不可重複，tick 的有效判定採用先見原則。

• 總供應量 = `amtPerMint` \* `mintCount`

• `metadata` 為自定義數據項目，可綁定代幣相關數據，可以包含簡介、圖片等

• `beginHeight` 和 `endHeight` 決定了該鑄造時間的有效時間範圍。`beginHeight` 如未指定有效區塊高度，則為 Deploy 该 PIN確認高度；`endHeight` 如未指定有效區塊高度，則代表無結束時間限制。

#### `premineCount` 說&#x660E;**：**

• 部署者可設置預挖參數，數值為在 deploy 交易中直接挖取指定次數的代幣

• 預挖的 Token 在 Deploy 交易確認時直接預挖到 Deploy 使用者地址上。

• 預挖總量 = `amtPerMint` \* `premineCount`

• `premineCount` 為選項，默認值為 0，取值範圍為 0\~mintCount，範圍之外的賦值視為無效

• 例子：一個 deploy 中設置為 `amtPerMint` = 10000, `mintCount` = 100, `premineCount` = 60，則視為 100 次的總挖取次數中預挖了 60 次，只有剩餘 40 次為公開的可鑄造次數

#### `payCheck` 說&#x660E;**：**

• 如果部署者設置了 `payCheck` 項目，則每次鑄造時均會檢查鑄造交易是否向指定地址支付了指定的 satoshi，如不符合要求則鑄造無效

• `payTo` 項目為鑄造時需向指定的地址轉入；`payAmount` 為鑄造時需向 `payTo` 地址轉移指定數量的 satoshi

#### `pinCheck` 說明

* 如果部署者設置了 `pinCheck` 項目，則每次鑄造時均會檢查鑄造交易中是否帶了指定條件的 PIN，如不符合要求則鑄造無效
* `creator` 為檢查 PIN 創建者是否為指定 MetaID&#x20;
* `path` 為檢查 PIN 所在路徑是否為指定的路徑
  * `path` 的格式請詳細查看 MetaID 協議關於 path 的說明
  * `path` 支持該 path payload 的內容匹配
  * `/path[‘payload’]` 匹配指定 path 位置下 payload 的全部內容
  * `/path[‘key’=’value’]` 匹配指定 path 位置下 payload 裡的 key 和 value 值
* `count` 為檢查符合條件的 PIN 的數量，默認值為 1
* `lvl` 為檢查 PIN 的等級是否符合要求。`lvl` 由 PIN 的 PoP 值決定，請詳細查看 PoP 值和 lvl 值說明
* `checkPin` 裡的 4 個參數可相互組合，形成可適應多場景的鑄造要求

#### **pinCheck示例**

```json
// 不限制路徑和難度及創建者，任意一個 PIN 均有鑄造資格
"pinCheck": {
  "count": "1"
}

// 需要一個 simplebuzz 協議的 PIN
"pinCheck": {
  "path": "/protocols/simplebuzz"
}

// 需要關注過特定 metaid 的 PIN
"pinCheck": {
  "path": "/follow['metaid_of_me']"
}

// 需要點贊過某個 PIN 的 PIN
"pinCheck": {
  "path": "/protocols/paylike['liketo'='abcdefgh...']"
}

// /protocols 下的任意協議的 PIN（2 個）均有鑄造資格
"pinCheck": {
  "path": "/protocols/*",
  "count": 2
}

// 需要擁有我的 PIN 才有鑄造資格
"pinCheck": {
  "creator": "abcdef0123457" // 需要 metaid 為“abcdef0123457”所創造的 pin
}
```

### 鑄造

#### PIN 路徑：`/ft/mrc20/mint`

後端索引器應只對符合路徑的 mint 資料做驗證和索引

該路徑下的 PIN 不接受 `modify` 和 `revoke`操作

#### 協議格式：

```tsx
{
  "id": "479f8579e5dcdbef868a61541f0d55efccfee1704c8a03f07fb1d97577104d53i0" // tokenID，這個 tokenID 是 deploy 交易的 PINID
}
```

#### 要點說明：

• 協議只有一個參數，就是 `id`，代表了要鑄造的 tokenid，tokenid 為 Deploy PIN對應的 PINID。

• 鑄造的 token 總量由 Deploy 的`amtPerMint` 參數決定。如成功鑄造，該次鑄造的 token 總量會轉移到 Mint 交易的第一個 output 的第一個 satoshi 上。

• 鑄造有效性由 indexer 服務決定，indexer 根據 Deploy 中的相關條件和約束規則驗證該鑄造交易是否合法。判斷的規則全都是鏈上數據，所以即便不同開發者開發的 indexer 的校驗結果也應該是一致的。

• 如 Deploy 檔有 `pinCheck` 要求時，Mint 交易 input 需要指向一個或多個有效 PIN 以完成 PIN 校驗。

• 一個 PIN 在同一個 token 的 mint event 中，只能使用一次。

• 如 Deploy PIN有 `payCheck` 要求時，Mint 交易需有一個 output 符合 `payCheck` 的地址和金額要求。

• Mint 不支持跨鏈鑄造，也就是說 Mint 交易必須和其對應的 Deploy 交易處於同一鏈中。

#### Mint 交易構建例子

<figure><img src="https://57349855-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNHx0f4Bxw8OTbRs9kele%2Fuploads%2FnCPuWyxE2xNmiufyOEbE%2Fimage.png?alt=media&#x26;token=2170a361-61a5-4797-a77c-52589aacc339" alt=""><figcaption><p>使用 Taproot 信封鑄造，該 mrc20 的鑄造條件中需要 3 個 pin（count: 3)，payCheck 條件為給 address xxx 地址支付 100000 聰 BTC。</p></figcaption></figure>

### Transfer 轉帳

{% hint style="info" %}
轉帳有兩種形式：原生轉帳和數據轉帳
{% endhint %}

#### 原生轉帳（直接轉帳）

原生轉帳是一種簡易的、Layer 1 的轉帳方式，不需要依靠寫入轉帳數據的方式，以純粹的 utxo 轉移方式完成。

原生轉帳適合於不需要 MRC20 代幣找零 的場景，如

1\. Alice 將自己的某種 MRC20 代幣 全部 轉移給 Bob。

2\. Alice 需要給 Bob 轉移的某種 MRC20 代幣的 數量剛好是其中一個或幾個 MRC20 UTXO 的數量之和。

#### 原生轉帳交易構造

當 input 中帶有 MRC20 UTXO，且交易中沒有指明轉帳數據（OPRETURN 或 taproot 數據），則所有 MRC 餘額轉入第一個非 OPRETURN 輸出中

<figure><img src="https://57349855-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNHx0f4Bxw8OTbRs9kele%2Fuploads%2FoPTWJCX9a7nigc6y3qzw%2Fimage.png?alt=media&#x26;token=60fc2609-4998-4a40-9c63-3f478180b32b" alt=""><figcaption><p>Native transfer</p></figcaption></figure>

### 數據轉帳 (MRC20 Allocation)

• 數據轉帳指通過 在 MetaID 規範的 Taproot 信封中顯式寫入轉帳說明數據 進行轉帳的方式。使用 JSON 格式。通過指定，規定該交易中傳入的 Input 中的 MRC20 餘額，分別分配到哪些 output 中。

• 數據轉帳適合於所有複雜的、需要有多個 output 分配的，或是需要進行餘額找零的交易類型。

• 數據轉帳使用的 PIN Path 為 `/ft/mrc20/transfer`

• 數據轉帳使用與 PIN 類似的數據結構，其中 operation 使用 `hide` 類型，不生成對應的 utxo，不帶有 pinId

• 如果分配方案超過了 input 中蘊含的 MRC20 數量的總額，則該分配視為無效 invalid，退回到缺省的直接轉帳機制，即當前交易中所有 MRC 餘額轉入第一個非 OPRETURN 輸出。

• input 中未被分配完的餘額，使用缺省的直接轉帳機制，自動賦予第一個非 OP\_RETURN 的輸出。可將該機制看作自動找零的行為，默認將未分配的餘額部份找零到第一個 output。

• 其他未被認可的數據轉帳寫法被視為非法，使用缺省的直接轉帳機制，此交易中的 MRC20 餘額將轉入第一個輸出。

#### 數據轉帳格式

數據轉帳寫在 MetaID 信封的 payload 中，以數組的形式存在。

```tsx
type MRC20AllocationItem = {
	id: string
	amount: string
	type?: 'transfer' | 'teleport' = 'transfer'
	vout?: number
	coord?: string
}

type MRC20Allocation = MRC20AllocationItem[]
```

#### 數據轉帳字段說明

* **`id`**: 分配的 MRC20 的 MRC20ID
* **`amount`**: 分配的 MRC20 數量
* **`type`**: 操作類型。有兩種類型：
  * **`transfer`**: （默認）轉帳，指該部份餘額轉到當前交易的某個輸出中。當類型為 transfer 時，需指定 vout
  * **`teleport`**：躍遷，指該部份餘額轉到非本鏈的某個 已存在 的 UTXO 中。當類型為 teleport 時，需指定 coord。躍遷的詳情請參考下一部份。
* **`vout`**: MRC20 分配到的 output index。
* **`coord`**：躍遷時 MRC20 分配到的非本鏈的 UTXO 的位置，以 ${txid}i${vout} 的形式表達。

#### 數據轉帳示例

* 以下 JSON 實例為 MetaID 協議規範中的 payload 項，外層需遵循 MetaID 信封規範。

```tsx
const allocation: MRC20Allocation = [
  {
    "amount": "100",
    "vout": 0,
    "id": "479f8579e5dcdbef868a61541f0d55efccfee1704c8a03f07fb1d97577104d53i0", // 'token1'
  },
  {
    "amount": "256",
    "vout": 3,
    "id": "bcccd98a7a1250f26b57d47cfdd36a95866d4bee59c32c9d4e71a6cc1f3429a5i0", // 'token2'
  },
  {
    "amount": "300",
    "vout": 3,
    "id": "479f8579e5dcdbef868a61541f0d55efccfee1704c8a03f07fb1d97577104d53i0", // 'token1'
  },
];

const pinData = {
	metaidFlag: 'metaid',
	operation: 'hide',
	path: '/ft/mrc20/transfer',
	contentType: 'application/json',
	payload: JSON.stringify(allocation) // 將分配數據進行 JSON 序列化放入 payload 字段
}
```

以上的轉帳交易中，100 個 token1 賦予給 index:0 輸出；256 個 token2 賦予給 index:3 輸出；300 個 token1 賦予給 index:3 輸出。

<figure><img src="https://57349855-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNHx0f4Bxw8OTbRs9kele%2Fuploads%2F6UbCXYWmmc2aN3bZQpKS%2Fimage.png?alt=media&#x26;token=1abf4959-a977-46ad-94fc-40df98bf9e5f" alt=""><figcaption><p>完全分配</p></figcaption></figure>

<figure><img src="https://57349855-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNHx0f4Bxw8OTbRs9kele%2Fuploads%2FcF7Uhj0LZ8fKH9Oj0DGO%2Fimage.png?alt=media&#x26;token=dc2d772f-3aca-4f77-85e4-9076a1d5835a" alt=""><figcaption><p>部分分配，未被指定分配的餘額將自動找零歸入第一個output</p></figcaption></figure>

<figure><img src="https://57349855-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNHx0f4Bxw8OTbRs9kele%2Fuploads%2F9W7CoZBXPaHX9IwHCN81%2Fimage.png?alt=media&#x26;token=8f78dda1-098e-4060-9800-4c77b199119e" alt=""><figcaption><p>無效分配，分配方案大於輸入中的餘額；此時無視分配方案，退回到缺省的直接轉帳機制</p></figcaption></figure>

## Teleport 躍遷（跨鏈）

### 躍遷示例

```tsx
const allocation: MRC20Allocation = [
  {
    amount: '100',
    id: '479f8579e5dcdbef868a61541f0d55efccfee1704c8a03f07fb1d97577104d53i0', // 'token1'
    coord: 'bcccd98a7a1250f26b57d47cfdd36a95866d4bee59c32c9d4e71a6cc1f3429a5i2', // 躍遷坐標，使用 pinId 結構定位 utxo
    type: 'teleport',
  },
]

const pinData = {
	metaidFlag: 'metaid',
	operation: 'hide',
	path: '/ft/mrc20/transfer',
	contentType: 'application/json',
	payload: JSON.stringify(allocation) // 將分配數據進行 JSON 序列化放入 payload 字段
}
```

* 躍遷實現了 MRC-20 的跨鏈功能；可以視為是 transfer 的擴維版本。transfer 將 MRC-20 餘額分配到本交易的 output 中，teleport 將餘額分配到其他鏈的 output 中。
* `coord`（坐標）使用另外鏈中的 `${txid}i${vout}` 格式來定位目標 utxo
* `coord` 指向的 utxo 由 indexer 來識別所在的鏈，無需在數據中表達
* 如果 `coord` 指向的 utxo 不存在（indexer 無法尋得），此交易依然視為有效，而 teleport 分配的餘額部份視為燃燒。
* teleport 可以同 transfer 並列於一個交易內，分配優先級高於 transfer

<figure><img src="https://57349855-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNHx0f4Bxw8OTbRs9kele%2Fuploads%2FphxrySsRW8wT2lZxi9z5%2Fimage.png?alt=media&#x26;token=26addc16-a699-42c5-874d-17add43cf15b" alt=""><figcaption><p>躍遷示例</p></figcaption></figure>

### Teleport 同 Transfer 可以同層

<figure><img src="https://57349855-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNHx0f4Bxw8OTbRs9kele%2Fuploads%2FDBsVSWUtJddLVIIX79xT%2Fimage.png?alt=media&#x26;token=3750fb53-b28b-4120-9a43-22a553533446" alt=""><figcaption><p>躍遷同轉移同時存在</p></figcaption></figure>
