# 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 研究`