# ERC20 範例
> 直接繼承 import 的 Openzepplin ERC20代幣
```solidity=
// contracts/GLDToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract CharmingFish is ERC20 {
constructor(uint256 initialSupply) ERC20("CharmingFish", "CMF") {
_mint(msg.sender, initialSupply);
}
function buyToken(address to, uint256 amount) public{
address owner = msg.sender;
_transfer(owner,to,amount);
}
}
```
> 直接手動刻出 ERC20標準 須具備的 Function (非完整 要補完interface)
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
//持有者A ONWER : 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
//持有者B : 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2
//持有者C : 0x17F6AD8Ef982297579C203069C1DbfFE4348c372
interface IERC20 {
function totalSupply() external view returns (uint256); //V
function balanceOf(address account) external view returns (uint256); //V
function transfer(address recipient, uint256 amount) external returns (bool); //V
function allowance(address owner, address spender) external view returns (uint256); //V
function approve(address spender, uint256 amount) external returns (bool); //V
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); //V
event Transfer(address indexed from, address indexed to, uint256 value); //V
event Approval(address indexed owner, address indexed spender, uint256 value); //V
}
contract ERC20TEST is IERC20
{
uint public totalSupply;
string public name;
string public symbol;
int public decimals;
address public owner;
mapping (address => uint256) public balanceOf;
mapping (address => mapping(address => uint256)) public allowance;
constructor(){
totalSupply = 10000;
name = "TOM";
decimals = 18;
symbol = "tom";
balanceOf[msg.sender]=10000;
owner = msg.sender;
}
function transfer(address recipient, uint256 amount) external returns (bool){
balanceOf[msg.sender] -= amount;
balanceOf[recipient] += amount;
emit Transfer(msg.sender,recipient,amount);
return true;
}
function approve(address spender, uint256 amount) external returns (bool){
allowance[msg.sender][spender] +=amount;
emit Approval(msg.sender,spender,amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool){
allowance[sender][msg.sender] -= amount;
balanceOf[recipient] += amount;
balanceOf[sender] -= amount;
emit Transfer(sender,recipient,amount);
return true;
}
}
```
<BR>
> ERC721 示範
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
interface IERC721Metadata {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns(string memory);
}
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
interface IERC721 {
// Event
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
// Query
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
// Transfer
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
//Approve
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool _approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
//下面這些並非標準的ERC721必備Function
//mint
function mint(address to, uint256 tokenId) external;
function safemint(address to, uint256 tokenId, bytes memory data) external;
function safemint(address to, uint256 tokenId) external;
//burn
function burn(uint256 tokenId) external ;
}
contract ERC721 is IERC721, IERC721Metadata, IERC165{
string _name;
string _symbol;
constructor(string memory name_, string memory symbol_){
_name = name_;
_symbol = symbol_;
}
function name() public view returns (string memory){
return _name;
}
function symbol() public view returns (string memory){
return _symbol;
}
//檢查之用
function supportsInterface(bytes4 interfaceId) public pure returns (bool){
return interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
mapping(address => uint256) _balances;
mapping(uint256 => address) _owners;
mapping(uint256 => address) _tokenApprovals;
mapping(address => mapping(address => bool)) _operatorApprovals;
mapping(uint256 => string) _tokenURIs;
function balanceOf(address owner) public view returns (uint256 balance){
require(owner != address(0),"ERROR: address 0 can't be owner!");
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view returns (address){
address owner = _owners[tokenId];
require(owner != address(0),"ERROR: tokenId is not valid Id!");
return owner;
}
function approve(address to, uint256 tokenId) public{
address owner = _owners[tokenId];
require(owner != to,"ERROR: owner == to");
require(owner == msg.sender || isApprovedForAll(owner,msg.sender),"ERROR: Caller is not owner / approved for all");
_tokenApprovals[tokenId] = to;
emit Approval(owner,to,tokenId);
}
function getApproved(uint256 tokenId) public view returns (address operator){
address owner = _owners[tokenId];
require(owner != address(0),"ERROR: token is not minted or is burn already");
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool _approved) public{
address owner = msg.sender;
require(owner != operator,"ERROR: Owner cannot be the operator!");
//下面這樣多此一舉又慢 思考!
// if(_approved)
// {
// _operatorApprovals[owner][operator] = true;
// emit ApprovalForAll(owner,operator,true);
// }
_operatorApprovals[owner][operator] = _approved;
emit ApprovalForAll(owner,operator,_approved);
}
function isApprovedForAll(address owner, address operator) public view returns (bool){
return _operatorApprovals[owner][operator];
}
function transferFrom(address from, address to, uint256 tokenId) public{
_transer(from,to,tokenId);
}
function _transer(address from, address to, uint256 tokenId) internal{
address owner = _owners[tokenId];
require(owner == from , "ERROR: Owner is not from address!");
require(msg.sender==owner || isApprovedForAll(owner,msg.sender) || getApproved(tokenId)==msg.sender,"ERROR: Permission denied!");
delete _tokenApprovals[tokenId];
_balances[from]-=1;
_balances[to]+=1;
_owners[tokenId] = to;
emit Transfer(from,to,tokenId);
}
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) public{
_safeTransfer(from,to,tokenId,data);
}
function safeTransferFrom(address from, address to, uint256 tokenId) public{
_safeTransfer(from, to, tokenId, "");
}
function _safeTransfer(address from, address to, uint256 tokenId,bytes memory data) internal{
_transer(from,to,tokenId);
require(_checkOnERC721Received(from,to,tokenId,data),"ERROR: ERC721 receiver is not implmeneted!");
}
//reference
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private returns (bool) {
if (to.code.length > 0 /* to is a contract*/) {
try IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
else {
return true;
}
}
function mint(address to, uint256 tokenId) public{
require(to != address(0),"ERROR: You can't mint the NFT to address 0x00");
address owner = _owners[tokenId];
require(owner == address(0),"ERROR: TokenId has been used!");
// _transer(address(0),to,tokenId); 用這段會比較浪費 不需要做這麼多檢查
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0),to,tokenId);
}
function safemint(address to, uint256 tokenId, bytes memory data) public{
mint(to,tokenId);
require(_checkOnERC721Received(address(0),to,tokenId,data),"ERROR: ERC721 receiver is not implmeneted!");
}
function safemint(address to, uint256 tokenId) public{
safemint(to,tokenId,"");
}
function burn(uint256 tokenId) public{
address owner = _owners[tokenId];
require(msg.sender==owner,"ERROR: You don't have this permission!");
_balances[owner] -= 1;
_owners[tokenId] = address(0);
//or delete _owners[tokenId];
delete _tokenApprovals[tokenId];
emit Transfer(owner,address(0),tokenId);
}
function tokenURI(uint256 tokenId) external view returns(string memory){
address owner = _owners[tokenId];
require(owner != address(0),"ERROR: tokenId is not valid");
return _tokenURIs[tokenId];
}
function setTokenURI (uint256 tokenId,string memory URI) public{
_tokenURIs[tokenId]=URI;
}
}
```
###### tags: `Lab 研究`