跳到主要内容

发行 ERC-20 代币

最简单的代币合约,部署到 OXN。本指南先讲标准流程,再讲如何加机密性。

标准 ERC-20

与以太坊一致。用 OpenZeppelin:

contracts/MyToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyToken is ERC20 {
constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
_mint(msg.sender, initialSupply);
}
}

部署——同 Quickstart: Hardhat

OXN 自动给你什么

不改代码,你的用户获得:

  • 加密 calldata——transfer(recipient, amount) 调用不向观察者暴露 recipientamount
  • 加密事件——Transfer(from, to, amount) 事件只有调用者(发送方)能解密。

接收方看不到通过全局索引器看到 transfer 事件,因为事件日志按调用者加密。如果你的代币应用依赖通知接收方,需要为此设计。

加机密余额

想让 balanceOf(user) 对除用户本人外的所有人返回 0,给 getter 加门控:

contracts/PrivateToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract PrivateToken is ERC20 {
// 授权他人看你的余额
mapping(address => mapping(address => bool)) private readApprovals;

constructor(uint256 initialSupply) ERC20("PrivateToken", "PRIV") {
_mint(msg.sender, initialSupply);
}

// 覆写标准 balanceOf 加门控
function balanceOf(address account) public view virtual override returns (uint256) {
if (msg.sender == account || readApprovals[account][msg.sender]) {
return super.balanceOf(account);
}
return 0;
}

function approveReader(address reader) external {
readApprovals[msg.sender][reader] = true;
}
}

这样工作正常调用方必须通过签名查询访问——见签名查询

处理接收方通知

因为加密 Transfer 事件对接收方不可见,选项:

  1. Emit 一份公开伴随事件,只带参与方(不含金额):

    event TransferHint(address indexed from, address indexed to);

    接收方监听这个知道该时候去查余额。

  2. 在合约里存"pending"标志,接收方通过签名查询读:

    mapping(address => uint256) private pendingIncomingCount;
  3. 链下通知(推送服务、后端)。与链无关。

完整带测试的例子

可运行版本见 OXN 示例仓库(带 Hardhat 测试)。

下一步