使用流程

生成地址

z-addr 地址. 即匿名地址, 该地址通过一个 sk 和 一个 d 唯一确定.
可以公布你的 z-addr 让别人转账给你, 其他的各种 key 都用来做某种操作. d 参数往往用来形成 HD 钱包, 可以认为是地址序列.
具体如下.

// sk: spending key => ask, nsk, ovk
// ask: spend authorizing key, 256 => ak
// nsk: proof authorizing key, 256 => nk
// ovk: outgoing viewing key, 256
// ivk: incoming viewing key, 256 => pkD
// d: diversifier, 11bytes
// pkD: the public key of the address, g_d^ivk
// pkD + d => z-addr

例如: ztron1m445gx74mjuuyhkyru5hrx886jszfga4a7dk3mg4uarrl0cru649jz4928tm6rqul2pg645hqv5

该地址格式为 bech32 格式, ztron1 为固定前缀. 后为编码的 pkDd 信息.

地址和 key 相关 API 如下:

wallet/getspendingkey
> generating sk

wallet/getexpandedspendingkey
> sk => aks, nsk, ovk

wallet/getakfromask
> ask => ak

wallet/getnkfromnsk
> nsk => nk

wallet/getincomingviewingkey
> ak, nk => ivk

wallet/getdiversifier
> generating d

wallet/getzenpaymentaddress
> ivk, d => z-addr, pkD

为了方便一次性生成地址, TRONZ 提供了 wallet/getnewshieldedaddress API, 支持一次性生成所有 Key 和地址.

> curl https://api.nileex.io/wallet/getnewshieldedaddress
{
  "sk": "03a7e......ommitted......71704fec2d3d",
  "ask": "c6ca0277c790......ommitted......1bd47713dc5074e0b",
  "nsk": "afc20d0......ommitted......4ae18ad62306",
  "ovk": "d893......ommitted......75476d6d84",
  "ak": "c682ba......ommitted......a2b411e7d134",
  "nk": "458d......ommitted......ea8b5408a4",
  "ivk": "847e......ommitted......5f40b6bb76400",
  "d": "82a05......ommitted......69f6812",
  "pkD": "7cd04d......ommitted......dd242f5bbdccdfce01",
  "payment_address": "ztron1s2s9fpf2v2l3d8......ommitted......4h0wvml8qzjzrv36"
}

匿名 TRC20 合约

合约地址 ShieldedTRC20.sol.

一个匿名 TRC20 合约, 必须绑定到一个已有的 TRC20 合约上. 如下是关键函数列表:

constructor (address trc20ContractAddress, uint256 scalingFactorExp)

function burn(bytes32[10] input, bytes32[2] spendAuthoritySignature, uint256 rawValue, bytes32[2] bindingSignature, address payTo, bytes32[3] c)
    => burn(bytes32[10],bytes32[2],uint256,bytes32[2],address,bytes32[3]) [4d013fde]

function mint(uint256 rawValue, bytes32[9] output, bytes32[2] bindingSignature, bytes32[21] c)
    => mint(uint256,bytes32[9],bytes32[2],bytes32[21]) [855d175e]

function transfer(bytes32[10][] input, bytes32[2][] spendAuthoritySignature, bytes32[9][] output, bytes32[2] bindingSignature, bytes32[21][] c)
    => transfer(bytes32[10][],bytes32[2][],bytes32[9][],bytes32[2],bytes32[21][]) [9110a55b]

function scalingFactor() view returns (uint256)
    => scalingFactor() [ed3437f8]
function getPath(uint256 position) view returns (bytes32, bytes32[32])
    => getPath(uint256) [e1765073]

基于 TRON 对该套 API 的封装, 实际使用不需要关注 burn, mint, transfer 函数的参数, 只需通过函数签名和工具 API 返回的字节串调用合约即可.

使用流程

第一步, 部署合约, 调用合约构造函数完成初始化

这里在 Nile Testnet 映射 JST token TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3 到匿名 TRC20 合约.

对应的匿名 TRC20 合约地址是 TEkQTDyZmbY6hngxdAsxzxy9r3bUNhRjdS. 构造函数参数为
(TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3, 18). 所以 scalingFactor 是 10 ** 18, 即 JST 的小数点位.

Solidity 编译器需要使用 https://github.com/tronprotocol/soliditydevelop 分支.

然后我们的初始地址 TJRabPrwbZy45sbavfcjinPJC18kjpRTv8 内通过 Nile Testnet 水龙头 地址获得测试用 JST token 代币.

给 z 地址转账 - 铸币 mint

转账前有一个重要操作, 使用 TRC20 的 approve 转账方式, 给匿名合约地址授权.

=> transferFrom(from: addr, to: addr, uint265)

授权 1000000 单位 TRC20 代币, 这样匿名 TRC20 合约就有权限使用 transferFrom 方式转账.

假设我们的目标地址是 ztron1s2s9fpf2v2l3d8mgzf7dqnfptkrlmyekvaqlw50lpf8dz8xkdgphjuxaysh4h0wvml8qzjzrv36.

先创建 rcm:

> curl https://api.nileex.io/wallet/getrcm
{"value": "720c84c8b41b3dcfcc1d5997e196e6de99f07aefb9274e285a23c5599ea2c40a"}

随后调用合约参数构造 API wallet/createshieldedcontractparameters:

{
  'from_amount': '10000',
  'shielded_receives': {'note': {
      'value': 1000,
      'payment_address': 'ztron1s2s9fpf2v2l3d8mgzf7dqnfptkrlmyekvaqlw50lpf8dz8xkdgphjuxaysh4h0wvml8qzjzrv36',
      'rcm': '720c84c8b41b3dcfcc1d5997e196e6de99f07aefb9274e285a23c5599ea2c40a',
      'memo': 'HEX'}},
  'shielded_TRC20_contract_address': '4148c0020ff778c4090bf196e39d51b92bf5a647b1'
}
  • 其中 from_amount 只能是字符串型
  • notevaluefrom_amount 除以 scalingFactor

得到若干参数, 其中最重要的是 trigger_contract_input

{'binding_signature': '......',
 'message_hash': '.....',
 'parameter_type': 'mint',
 'receive_description': [{'c_enc': '..........',
                          'c_out': '.....',
                          'epk': '...',
                          'note_commitment': '.....',
                          'value_commitment': '.....',
                          'zkproof': '.....'}],
 'trigger_contract_input': '.....'
}

[855d175e](mint 函数的签名) 拼接 trigger_contract_input, 得到调用合约 mint 函数的最终参数, 使用发送地址调用合约并签名广播即可.

交易 https://nile.tronscan.org/#/transaction/e191f1114cbd8cbe43452b2c3141326ae4c2aba22a82ba195c9573895cbbfd84

查询转入转账

使用 wallet/scanshieldedtrc20notesbyivk API.

提供 z-addr 的 ivk, ak, nk 返回 Note 列表. 一次只能扫描 1000 个区块.

返回的 Note 会附带 is_spent 信息.

z 地址之间相互转账 - transfer

转账基于 Note 到 Note, 可以是 1-2 个 note 转入 1-2 个 note, 金额必须平衡, 使用找零机制。

需要注意的是 alpha, rcm 均为随机数。需要通过 wallet/getrcm 获取.

例子 txid: f0274768b212cf1729a137926980315be04ff46d265416183d85a97bccc68b8b

查询转出转账

使用 wallet/scanshieldedtrc20notesbyovk API

提供 z-addr 的 ovk. 查询转出的 note 列表.

返回的 Note 不带 is_spent 字段, 但 is_spent = True.

查询 Note 是否被花掉

使用 wallet/isshieldedtrc20contractNoteSpent API. 提供 ak, nk.

z 地址转入到透明地址 - burn

操作及 key 参数同 transfer.

参考文档

详细文档