Solana的代币与以太坊代币的区别
1- SPL Token
1.1- 基于 Solana 区块链
1.2- 采用 Rust 原生程序编写
1.3- 账户模型:一个代币一个mint账户,每个用户,每个代币数据都存储在独立账户中
每个用户的代币账户(token account)由mint、user Account计算得到:
如:前端可以由以下代码生成:
const referrerAta = await getAssociatedTokenAddress(
mint, // mint公钥
wallet.publicKey, // 创建人公钥
false, // 是否在椭圆曲线上,如果是EOA账户创建,用false,如果是PDA账户创建,为true
TOKEN_PROGRAM_ID // SPL Token程序地址
)
后端由以下代码生成:
let ata = get_associated_token_address_with_program_id(
&ctx.accounts.payer.key(),
&ctx.accounts.mint.key(),
&ctx.accounts.token_program.key(),
);
也就是说,涉及到代币的账户有以下几个:
- 1- mint account:铸币账户,一个代币对应一个铸币账户;
- 2- token account:用户的代币账户,每个用户的每个代币对应一个token account,相当于在银行的外汇户头,每个外汇有一个账户。
-
3- EOA账户:即外部账户,也就是普通账户,在钱包里看到的账户,用于存储SOL原生代币,以及派生出各个token account,相当于银行的主账户。
- 优点:提升安全性
- 缺点:增加账户管理成本,比如要对一个代币解锁,需要对所有持有人账户都进行一个一个解锁
1.4- 交易延迟 400ms / 吞吐量 50k+ TPS
1.5- 主要钱包:Phantom、Solflare等
2- ERC20
2.1- 基于 EVM 虚拟机
2.2- 采用 Solidity 编写智能合约
2.3- 地址模型:所有用户的代币数据都存在一个ERC20智能合约中,直接存储于钱包地址
如以下代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MiniERC20 {
// 代币元数据
string public constant name = "SimpleToken";
string public constant symbol = "ST";
uint8 public constant decimals = 18;
// 核心数据结构
mapping(address => uint256) private _balances; // <--- 保存不同账户的余额的mapping
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
// 必须事件
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
constructor(uint256 initialSupply) {
_mint(msg.sender, initialSupply * 10**decimals);
}
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public returns (bool) {
_transfer(msg.sender, to, amount);
return true;
}
function allowance(address owner, address spender) public view returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
function transferFrom(address from, address to, uint256 amount) public returns (bool) {
_spendAllowance(from, msg.sender, amount);
_transfer(from, to, amount);
return true;
}
// 转账的内部核心逻辑
function _transfer(address from, address to, uint256 amount) internal {
require(from != address(0), "ERC20: transfer from zero address");
require(to != address(0), "ERC20: transfer to zero address");
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: insufficient balance");
_balances[from] = fromBalance - amount;
_balances[to] += amount;
emit Transfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal {
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
}
function _approve(address owner, address spender, uint256 amount) internal {
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _spendAllowance(address owner, address spender, uint256 amount) internal {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
_approve(owner, spender, currentAllowance - amount);
}
}
ERC20中关于用户代币余额都保存在_balance[]
中,转账代码是:
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: insufficient balance");
_balances[from] = fromBalance - amount;
_balances[to] += amount;
- 优点:管理简便,如对一个代币解锁,只要给代币设置一个属性即可,无需操作所有持有人的账户。
- 缺点:安全性较差
2.4- 交易延迟15秒 / 吞吐量~30 TPS
2.5- 主要钱包:Metamask、OKX、TrustWallet等