MRC-20

MRC-20 是基于 MetaID 的一个 Fungible Token 发行协议,用户可以通过 MRC-20 协议发行资产并制定铸造方式。与其他资产发行协议相比,MRC-20 协议最大的特点是其发行方式能够与个人链数据以及 MetaID 协议紧密结合,从而满足各种链上活动的资产发行需求。简单来说,MRC-20 是一种为满足日后各种 Web3 活动而制定的 Fungible Token 发行协议。

协议格式

部署

PIN 路径/ft/mrc20/deploy

后端索引器应只对符合路径的 PIN 做验证和索引。

  • 该路径下的 PIN 不接受 modifyrevoke 操作。

协议格式

{
  "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 为自定义数据项,可绑定代币相关数据,可以包含简介、图片等。

  • beginHeightendHeight 决定了铸造时间的有效时间范围。beginHeight 如未指定有效区块高度,则为 Deploy 该 PIN 确认高度;endHeight 如未指定有效区块高度,则代表无结束时间限制。

premineCount 说明

  • 部署者可设置预挖参数,数值为在 deploy 交易中直接挖取指定次数的代币。

  • 预挖的 Token 在 Deploy 交易确认时直接预挖到 Deploy 使用者地址上。

  • 预挖总量 = amtPerMint * premineCount

  • premineCount 为选项,默认值为 0,取值范围为 0~mintCount,范围之外的赋值视为无效。

  • 例子:一个 deploy 中设置为 amtPerMint = 10000, mintCount = 100, premineCount = 60,则视为 100 次的总挖取次数中预挖了 60 次,只有剩余 40 次为公开的可铸造次数。

payCheck 说明

  • 如果部署者设置了 payCheck 项目,则每次铸造时均会检查铸造交易是否向指定地址支付了指定的 satoshi,如不符合要求则铸造无效。

  • payTo 项目为铸造时需向指定的地址转入;payAmount 为铸造时需向 payTo 地址转移指定数量的 satoshi。

pinCheck 说明

如果部署者设置了 pinCheck 项目,则每次铸造时均会检查铸造交易中是否带了指定条件的 PIN,如不符合要求则铸造无效。

  • creator 为检查 PIN 创建者是否为指定 MetaID。

  • 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 示例

  • 不限制路径和难度及创建者,任意一个 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 不接受 modifyrevoke 操作。

协议格式

{
  "id": "479f8579e5dcdbef868a61541f0d55efccfee1704c8a03f07fb1d97577104d53i0" // tokenID,这个 tokenID 是 deploy 交易的 PINID
}

要点说明

  • 协议只有一个参数,就是 id,代表了要铸造的 tokenidtokenid 为 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 交易构建例子

Transfer 转账

转账有两种形式:原生转账和数据转账。

原生转账(直接转账)

原生转账是一种简易的、Layer 1 的转账方式,不需要依靠写入转账数据的方式,以纯粹的 UTXO 转移方式完成。

原生转账适用于不需要 MRC20 代币找零的场景,如:

  1. Alice 将自己的某种 MRC20 代币 全部 转移给 Bob。

  2. Alice 需要给 Bob 转移的某种 MRC20 代币的数量刚好是其中一个或几个 MRC20 UTXO 的数量之和。

原生转账交易构造

input 中带有 MRC20 UTXO,且交易中没有指明转账数据(如 OPRETURN 或 Taproot 数据),则所有 MRC20 余额将转入第一个非 OPRETURN 输出中。

数据转账 (MRC20 Allocation)

  • 数据转账指通过在 MetaID 规范的 Taproot 信封中显式写入转账说明数据进行转账的方式。使用 JSON 格式,通过指定的规则,规定交易中传入的 input 中的 MRC20 余额分别分配到哪些 output 中。

  • 数据转账适用于所有复杂的、需要有多个 output 分配的,或是需要进行余额找零的交易类型。

  • 数据转账使用的 PIN Path 为 /ft/mrc20/transfer

  • 数据转账使用与 PIN 类似的数据结构,其中 operation 使用 hide 类型,不生成对应的 UTXO,不带有 pinId

  • 如果分配方案超过了 input 中包含的 MRC20 数量的总额,则该分配视为无效(invalid),退回到缺省的直接转账机制,即当前交易中所有 MRC20 余额转入第一个非 OPRETURN 输出中。

  • input 中未被分配完的余额,使用缺省的直接转账机制,自动赋予第一个非 OP_RETURN 的输出。可以将该机制看作自动找零的行为,默认将未分配的余额部分找零到第一个输出。

  • 其他未被认可的数据转账写法被视为非法,使用缺省的直接转账机制,此交易中的 MRC20 余额将转入第一个输出。

示例代码

const allocation = [
  {
    "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 输出。

Teleport 跨链

跨链示例

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 字段
}

功能说明

Teleport 实现了 MRC-20 的跨链功能,可以视为 transfer 的扩展版本。

  • transfer:将 MRC-20 余额分配到本交易的 output 中。

  • teleport:将余额分配到其他链的 output 中。

coord(坐标)

  • 格式:使用另外链中的 ${txid}i${vout} 格式来定位目标 utxo。

  • 链识别:coord 指向的 utxo 由 indexer 识别所在链,无需在数据中直接表述。

错误处理

如果 coord 指向的 utxo 不存在(indexer 无法找到),此交易依然视为有效,而 teleport 分配的余额部分视为燃烧。

与 transfer 的关系

  • teleport 可以与 transfer 并列于一个交易内。

  • 优先级:分配优先级高于 transfer。

Teleport 与 Transfer 可以同层

Last updated