发行 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)调用不向观察者暴露recipient或amount。 - 加密事件——
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 事件对接收方不可见,选项:
-
Emit 一份公开伴随事件,只带参与方(不含金额):
event TransferHint(address indexed from, address indexed to);接收方监听这个知道该时候去查余额。
-
在合约里存"pending"标志,接收方通过签名查询读:
mapping(address => uint256) private pendingIncomingCount; -
链下通知(推送服务、后端)。与链无关。
完整带测试的例子
可运行版本见 OXN 示例仓库(带 Hardhat 测试)。