全部动态

89 条动态
Leo
Leo置顶

支付中的各种二维码

在工作中经常要使用或验证各种二维码,做了一个整理

二维码类型二维码图片二维码原文
境外银联EMV二维码 000201010211153147980344000203447980344599900015204599953033445802HK5923BOCI – MBD – CUP – MPOS6009Hong Kong626001200000000000000000000005200000000000000000000007089999610163046be1
FPS二维码 0002010102125204000053033445406291.005802HK5902NA6002HK26270012hk.com.hkicl0207173606562290525015635700419081421032241163040490
Common QR Code
0002010102111531257803440052044659991249790824626270012hk.com.hkicl020776090275204599953033445802HK5912BoC Bill LVT6002HK6238052201-CILFPS20032300017030708279082466304B758
八达通商户码octopus://qrpayment?token=OEM0303432040114904B68B
香港AlipayHK收款码https://qr.alipay.hk/281004052018081919053106000400008945
境内银联二维码https://qr.95516.com/00010002/62225349542615512535760397834354
境内微信个人静态码wxp://f2f0qa_fsPnKMI5UzB1JhpIF1AOEXb9CKUGh
境内微信商户静态码(1)https://payapp.weixin.qq.com/qrpay/order/home2?key=idc_CHNDVI_eHdIbTNZIWPIrrYD0SBWHA–
境内微信商户静态码(2)https://payapp.weixin.qq.com/qrpay/order/home2?key=idc_CHNDVI_RR_7bDNZIWNH.M0dAJLICw–
境内微信商户动态码weixin://wxpay/bizpayurl?pr=ZAGsMVdzz
*单次有效,再次扫码会报错
境外微信个人码wxp://wbf2f02OodBKgfVvgS80xnHfYApw/9QLgCOcRkjNdGHu6YLu8VnJ0unL60Foq0qKIGOcz6w
香港商户收款码00020101021126160012hk.com.hkicl32540016hk.com.wechatpay0102020224WcFHo_pMPiD3hui8sAOpWQ==6304B046
支付宝个人码HTTPS://QR.ALIPAY.COM/FKX06550EGBGYWCOEUBCED
支付宝商户码https://qr.alipay.com/stx04435s4w2lcji4osvu91
银联标准聚合码https://qr.95516.com/01041220/13789d6e-a6a8-48b9-ae39-f6da36876d37
非银联标准聚合码(互联互通-银联商务码)https://qr.chinaums.com/bills/qrCode.do?id=10002007146065434148290549
境外支付宝微信聚合码https://app.wepayez.com/spay/scanQr?qrcodeId=6B4C0G4I7EBF1JAE4D4J2I2EQIIDNWqo
数字人民币商户主扫码(1)https://qr.test.com/004031000023870125000000000000000000000
数字人民币商户主扫码(2)https://qr.pbcdci.cn/004032000049640436000000000000000000000
数字人民币个人被扫支付码0100400727533557272
注:为保护隐私,内容做过调整,格式是19位数字
数字人民币个人被扫收款码https://qr.pbcdci.cn/0040110000314816627
注:为保护隐私,内容做过调整。
数字人民币微信支付宝银联聚合码https://q.huijingcai.cn/122062300100936828
支持数字人民币的微信商户收款码https://payapp.weixin.qq.com/materialqr/entry/home?id=00186350265397
支持数字人民币的个人收款码(暂不支持商户收款码,香港852手机号不支持个人收款码)https://qr.alipay.com/fkx120953fv6qs7bdwj6x37
支持数字人民币的银联标准聚合码https://qr.95516.com/01040000/0254110730007488653886?orderType=10&merChannel=BCAS
以太坊个人收款码(标准)0x2e5ebb702f66eba8d0469112ce3160c41d8967c6
以太坊并没有统一的的二维码标准,火币的收款QR就是标准eth地址
以太坊个人收款码(imToken)ethereum:0xDb5206169c8c491BC8B17d294DbaFF6644df889B?decimal=18&value=0
以太坊并没有统一的的二维码标准,imToken的收款QR自己实现了一个ethereum协议,便于封装自己的参数例如收款金额
Leo

区块链系列3 – 如何发布支持预授权的ERC20代币

接着上一篇“区块链系列2 – 如何发布一个支持黑名单管理的ERC20代币” ,对于发币来说,默认的只支持主动转账的ERC20代币有时会有限制,在传统银行业务中,还有一个场景是授权交易,比如A账户可以发起一个授权,允许B账户在一定时间内向自己的账户发起扣款X元,这里的B账户、时间范围、累计扣款金额就是三个参数,那是否可以基于区块链开发一个这样的智能合约?即允许一个钱包用户授权另一个钱包客户在一定时间范围内一定金额范围内向自己的钱包发起扣款。经过我尝试,是可以的。

智能合约

预授权功能实现

重点内容:自托管钱包比如MetaMask它只有基础的转账和收款功能,如果是一个授权,是需要调用智能合约的一个方法,MetaMask是做不到的,所以就需要一个独立的DApp才可以,在自己开发的DApp里主动让钱包的私钥签名后调用特定的授权方法。

DApp开发

现在都有很成熟的DApp开发框架,很多语言也都可以实现,为了实现方式,我才用了php。

开发好的网址是: https://token.liangdong.me ,如下图所示

选择链

管理员权限

MetaMask选择测试链,并选择发布合约相同的钱包,即可看到管理员的功能,可以看到有100万代币,精读是2。

创建预授权

现在准备验证发起预授权,首先使用另外一个钱包, 0x207C3fF50e568a6DfEFB34FdDAd36faB69648Aa6 ,先使用管理员钱包0xDb5206169c8c491BC8B17d294DbaFF6644df889B 向这个钱包铸币1000

切换到0x207C3fF50e568a6DfEFB34FdDAd36faB69648Aa6钱包后即可看到余额

现在就可以发起预授权,授权0xDb5206169c8c491BC8B17d294DbaFF6644df889B钱包可以在1小时内授权累计500,不区分次数,总额不超过500即可。

点击创建预授权时需要通过Meta Mask签名,签名时也会看到信息,

Authorize 0xDb5206169c8c491BC8B17d294DbaFF6644df889B to spend 50000 wei of IOCT4CM. Valid for 1 hours.

这笔签名需要Gas Fee

预授权成功

可查询到该笔预授权,关键信息时预授权ID,后续可以通过这个预授权ID发起扣款交易,当然前提是只有允许被授权的钱包0xDb5206169c8c491BC8B17d294DbaFF6644df889B才可以通过这个ID发起授权扣款,其他钱包不可以。

发起预授权

现在把MetaMask切回到可以发起预授权的钱包0xDb5206169c8c491BC8B17d294DbaFF6644df889B ,输入预授权ID,输入金额100,点击执行扣款。

授权完成后各钱包查询

授权钱包余额900

Leo

区块链系列2 – 如何发布一个支持黑名单管理的ERC20代币

接着上一篇“区块链系列1 – 如何在以太坊发布一个带图标带官网的ERC20代币” ,对于发币来说,肯定希望增加黑名单管理的功能,比如动态增加黑名单、删除黑名单,这又分为付款黑名单 和 收款黑名单,这就会有几个问题。

  • 黑名单保存在哪里?
  • 可以通过一个URL来配置黑名单吗?
  • MetaMask这样的Web3 Wallet可以使用这种ERC20代币吗?
  • 在智能合约里配置因黑名单造成转账失败的错误提示,可以被查看吗?

一、Talk is cheap. Show me the code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

contract ERC20BlackList is ERC20, Ownable {
    // 黑名单结构体,包含状态和时间信息
    struct BlackListInfo {
        bool isBlacklisted;
        uint256 addedTime;
        uint256 removedTime;
    }
    
    mapping(address => BlackListInfo) public blackPayerList;
    mapping(address => BlackListInfo) public blackPayeeList;
    
    event BlackPayerAdded(address indexed account, uint256 addedTime);
    event BlackPayerRemoved(address indexed account, uint256 removedTime);
    event BlackPayeeAdded(address indexed account, uint256 addedTime);
    event BlackPayeeRemoved(address indexed account, uint256 removedTime);
    
    constructor() ERC20("IOC Team Token V2 BlackList", "IOCV2BL") Ownable(msg.sender) {
        _mint(msg.sender, 10000 * 10**decimals());
    }
    
    function _update(address from, address to, uint256 value) internal override {
        // 检查付款人黑名单
        if (from != address(0)) {
            require(!blackPayerList[from].isBlacklisted, "Transfer failed: sender address is blacklisted");
        }
        
        // 检查收款人黑名单
        if (to != address(0)) {
            require(!blackPayeeList[to].isBlacklisted, "Transfer failed: recipient address is blacklisted");
        }
        
        super._update(from, to, value);
    }
    
    // =============================================================
    // 付款人黑名单管理功能
    // =============================================================
    
    // 添加单个地址到付款人黑名单
    function addBlackPayer(address account) external onlyOwner {
        require(account != address(0), "Cannot add zero address");
        require(!blackPayerList[account].isBlacklisted, "Address already in payer blacklist");
        
        blackPayerList[account].isBlacklisted = true;
        blackPayerList[account].addedTime = block.timestamp;
        
        emit BlackPayerAdded(account, block.timestamp);
    }
    
    // 移除单个地址从付款人黑名单
    function removeBlackPayer(address account) external onlyOwner {
        require(blackPayerList[account].isBlacklisted, "Address not in payer blacklist");
        
        blackPayerList[account].isBlacklisted = false;
        blackPayerList[account].removedTime = block.timestamp;
        
        emit BlackPayerRemoved(account, block.timestamp);
    }
    
    // 批量添加付款人黑名单
    function batchAddBlackPayers(address[] memory accounts) external onlyOwner {
        require(accounts.length > 0, "Address list cannot be empty");
        uint256 currentTime = block.timestamp;
        
        for (uint256 i = 0; i < accounts.length; i++) {
            address account = accounts[i];
            require(account != address(0), "Cannot add zero address");
            
            if (!blackPayerList[account].isBlacklisted) {
                blackPayerList[account].isBlacklisted = true;
                blackPayerList[account].addedTime = currentTime;
                emit BlackPayerAdded(account, currentTime);
            }
        }
    }
    
    // 批量移除付款人黑名单
    function batchRemoveBlackPayers(address[] memory accounts) external onlyOwner {
        require(accounts.length > 0, "Address list cannot be empty");
        uint256 currentTime = block.timestamp;
        
        for (uint256 i = 0; i < accounts.length; i++) {
            address account = accounts[i];
            
            if (blackPayerList[account].isBlacklisted) {
                blackPayerList[account].isBlacklisted = false;
                blackPayerList[account].removedTime = currentTime;
                emit BlackPayerRemoved(account, currentTime);
            }
        }
    }
    
    // =============================================================
    // 收款人黑名单管理功能
    // =============================================================
    
    // 添加单个地址到收款人黑名单
    function addBlackPayee(address account) external onlyOwner {
        require(account != address(0), "Cannot add zero address");
        require(!blackPayeeList[account].isBlacklisted, "Address already in payee blacklist");
        
        blackPayeeList[account].isBlacklisted = true;
        blackPayeeList[account].addedTime = block.timestamp;
        
        emit BlackPayeeAdded(account, block.timestamp);
    }
    
    // 移除单个地址从收款人黑名单
    function removeBlackPayee(address account) external onlyOwner {
        require(blackPayeeList[account].isBlacklisted, "Address not in payee blacklist");
        
        blackPayeeList[account].isBlacklisted = false;
        blackPayeeList[account].removedTime = block.timestamp;
        
        emit BlackPayeeRemoved(account, block.timestamp);
    }
    
    // 批量添加收款人黑名单
    function batchAddBlackPayees(address[] memory accounts) external onlyOwner {
        require(accounts.length > 0, "Address list cannot be empty");
        uint256 currentTime = block.timestamp;
        
        for (uint256 i = 0; i < accounts.length; i++) {
            address account = accounts[i];
            require(account != address(0), "Cannot add zero address");
            
            if (!blackPayeeList[account].isBlacklisted) {
                blackPayeeList[account].isBlacklisted = true;
                blackPayeeList[account].addedTime = currentTime;
                emit BlackPayeeAdded(account, currentTime);
            }
        }
    }
    
    // 批量移除收款人黑名单
    function batchRemoveBlackPayees(address[] memory accounts) external onlyOwner {
        require(accounts.length > 0, "Address list cannot be empty");
        uint256 currentTime = block.timestamp;
        
        for (uint256 i = 0; i < accounts.length; i++) {
            address account = accounts[i];
            
            if (blackPayeeList[account].isBlacklisted) {
                blackPayeeList[account].isBlacklisted = false;
                blackPayeeList[account].removedTime = currentTime;
                emit BlackPayeeRemoved(account, currentTime);
            }
        }
    }
    
    // =============================================================
    // 黑名单检查功能(带时间信息)
    // =============================================================
    
    // 检查地址是否在付款人黑名单中
    function isBlackPayer(address account) external view returns (bool) {
        return blackPayerList[account].isBlacklisted;
    }
    
    // 检查地址是否在收款人黑名单中
    function isBlackPayee(address account) external view returns (bool) {
        return blackPayeeList[account].isBlacklisted;
    }
    
    // 获取付款人黑名单详细信息
    function getBlackPayerInfo(address account) external view returns (
        bool isBlacklisted,
        uint256 addedTime,
        uint256 removedTime
    ) {
        BlackListInfo memory info = blackPayerList[account];
        return (info.isBlacklisted, info.addedTime, info.removedTime);
    }
    
    // 获取收款人黑名单详细信息
    function getBlackPayeeInfo(address account) external view returns (
        bool isBlacklisted,
        uint256 addedTime,
        uint256 removedTime
    ) {
        BlackListInfo memory info = blackPayeeList[account];
        return (info.isBlacklisted, info.addedTime, info.removedTime);
    }
    
    // 检查地址在两个黑名单中的状态
    function getBlackListStatus(address account) external view returns (
        bool isPayerBlacklisted,
        bool isPayeeBlacklisted
    ) {
        return (
            blackPayerList[account].isBlacklisted,
            blackPayeeList[account].isBlacklisted
        );
    }
    
    // 获取地址的完整黑名单信息
    function getFullBlackListInfo(address account) external view returns (
        bool isPayerBlacklisted,
        uint256 payerAddedTime,
        uint256 payerRemovedTime,
        bool isPayeeBlacklisted,
        uint256 payeeAddedTime,
        uint256 payeeRemovedTime
    ) {
        BlackListInfo memory payerInfo = blackPayerList[account];
        BlackListInfo memory payeeInfo = blackPayeeList[account];
        
        return (
            payerInfo.isBlacklisted,
            payerInfo.addedTime,
            payerInfo.removedTime,
            payeeInfo.isBlacklisted,
            payeeInfo.addedTime,
            payeeInfo.removedTime
        );
    }
    
    // 批量检查多个地址的付款人黑名单状态
    function batchCheckBlackPayers(address[] memory accounts) external view returns (bool[] memory) {
        bool[] memory results = new bool[](accounts.length);
        for (uint256 i = 0; i < accounts.length; i++) {
            results[i] = blackPayerList[accounts[i]].isBlacklisted;
        }
        return results;
    }
    
    // 批量检查多个地址的收款人黑名单状态
    function batchCheckBlackPayees(address[] memory accounts) external view returns (bool[] memory) {
        bool[] memory results = new bool[](accounts.length);
        for (uint256 i = 0; i < accounts.length; i++) {
            results[i] = blackPayeeList[accounts[i]].isBlacklisted;
        }
        return results;
    }
    
    // 批量获取付款人黑名单详细信息
    function batchGetBlackPayerInfo(address[] memory accounts) external view returns (
        bool[] memory isBlacklistedList,
        uint256[] memory addedTimeList,
        uint256[] memory removedTimeList
    ) {
        uint256 length = accounts.length;
        isBlacklistedList = new bool[](length);
        addedTimeList = new uint256[](length);
        removedTimeList = new uint256[](length);
        
        for (uint256 i = 0; i < length; i++) {
            BlackListInfo memory info = blackPayerList[accounts[i]];
            isBlacklistedList[i] = info.isBlacklisted;
            addedTimeList[i] = info.addedTime;
            removedTimeList[i] = info.removedTime;
        }
        
        return (isBlacklistedList, addedTimeList, removedTimeList);
    }
    
    // =============================================================
    // 通用批量更新功能(兼容您原来的需求)
    // =============================================================
    
    // 批量更新付款人黑名单(支持添加和移除)
    function updateBlackPayerList(address[] memory addresses, bool[] memory statuses) external onlyOwner {
        require(addresses.length == statuses.length, "Address and status arrays length mismatch");
        require(addresses.length > 0, "Address list cannot be empty");
        uint256 currentTime = block.timestamp;
        
        for (uint256 i = 0; i < addresses.length; i++) {
            address account = addresses[i];
            bool status = statuses[i];
            require(account != address(0), "Cannot update zero address");
            
            if (blackPayerList[account].isBlacklisted != status) {
                blackPayerList[account].isBlacklisted = status;
                
                if (status) {
                    blackPayerList[account].addedTime = currentTime;
                    emit BlackPayerAdded(account, currentTime);
                } else {
                    blackPayerList[account].removedTime = currentTime;
                    emit BlackPayerRemoved(account, currentTime);
                }
            }
        }
    }
    
    // 批量更新收款人黑名单(支持添加和移除)
    function updateBlackPayeeList(address[] memory addresses, bool[] memory statuses) external onlyOwner {
        require(addresses.length == statuses.length, "Address and status arrays length mismatch");
        require(addresses.length > 0, "Address list cannot be empty");
        uint256 currentTime = block.timestamp;
        
        for (uint256 i = 0; i < addresses.length; i++) {
            address account = addresses[i];
            bool status = statuses[i];
            require(account != address(0), "Cannot update zero address");
            
            if (blackPayeeList[account].isBlacklisted != status) {
                blackPayeeList[account].isBlacklisted = status;
                
                if (status) {
                    blackPayeeList[account].addedTime = currentTime;
                    emit BlackPayeeAdded(account, currentTime);
                } else {
                    blackPayeeList[account].removedTime = currentTime;
                    emit BlackPayeeRemoved(account, currentTime);
                }
            }
        }
    }
    
    // =============================================================
    // 时间相关的查询功能
    // =============================================================
    
    // 查询在指定时间段内被添加到付款人黑名单的地址数量
    // 注意:这个函数需要遍历所有地址,实际使用中可能需要使用事件日志来实现
    // 这里只是示例,实际实现可能需要离链查询事件
    function getBlackPayersAddedInTimeRange(uint256 /*startTime*/, uint256 /*endTime*/) external pure returns (uint256) {
        // 占位返回 - 实际实现需要事件日志查询
        return 0;
    }
    
    // 检查地址是否在指定时间被加入黑名单
    function wasBlacklistedAt(address account, uint256 timestamp, bool isPayer) external view returns (bool) {
        BlackListInfo memory info = isPayer ? blackPayerList[account] : blackPayeeList[account];
        
        if (info.addedTime == 0) {
            return false; // 从未被加入黑名单
        }
        
        if (info.addedTime > timestamp) {
            return false; // 在指定时间后才被加入
        }
        
        if (info.removedTime > 0 && info.removedTime <= timestamp) {
            return false; // 在指定时间前已被移除
        }
        
        return true; // 在指定时间确实在黑名单中
    }
    
    // =============================================================
    // 实用工具函数
    // =============================================================
    
    // 获取当前区块时间戳
    function getCurrentTimestamp() external view returns (uint256) {
        return block.timestamp;
    }
    
    // 将时间戳转换为可读日期(需要前端处理)
    function getReadableTime(uint256 timestamp) external pure returns (string memory) {
        if (timestamp == 0) {
            return "Never set";
        }
        // 返回时间戳,前端可以转换为可读格式
        return string(abi.encodePacked("Timestamp: ", uint2str(timestamp)));
    }
    
    // 数字转字符串的辅助函数
    function uint2str(uint256 _i) internal pure returns (string memory) {
        if (_i == 0) {
            return "0";
        }
        uint256 j = _i;
        uint256 len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint256 k = len;
        while (_i != 0) {
            k = k - 1;
            uint8 temp = (48 + uint8(_i - _i / 10 * 10));
            bytes1 b1 = bytes1(temp);
            bstr[k] = b1;
            _i /= 10;
        }
        return string(bstr);
    }
    
    // 获取合约基本信息
    function getContractInfo() external view returns (
        string memory tokenName,
        string memory tokenSymbol,
        uint8 tokenDecimals,
        uint256 tokenTotalSupply,
        address contractOwner
    ) {
        return (
            name(),
            symbol(),
            decimals(),
            totalSupply(),
            owner()
        );
    }
}

看了代码后,就可以解决前两个问题了

  • 黑名单保存在哪里?
    • 保存在区块链上。
  • 可以通过一个URL来配置黑名单吗?
    • 不能,智能合约无法直接发起HTTP请求来检查外部URL,因为区块链是封闭的环境。

关于黑名单在区块链保存在哪里?可以参考下图会清晰一些:

二、发布合约到测试链Sepolia

还是使用Remix来部署合约,操作可以参考上一篇。

部署这个合约需要0.0062个ETH,主链的话就需要15美金,上一篇介绍的一个最简单的ERC20合约只需要3美金,毕竟这个代码很复杂,15美金也是正常的。

合约地址是: https://sepolia.etherscan.io/address/0x244af7a9faf2e494dfee1717e08e0a32fdbc9934

代币名称:IOCV2BL ,发行总量10000个。

三、需要公开代码,方便在线调用函数

把合约代码公开后,就可以在合约地址 https://sepolia.etherscan.io/token/0x244af7a9faf2e494dfee1717e08e0a32fdbc9934#code 直接读取合约或者写合约了,读合约的主要操作就是查询某个地址是否是黑明单,写合约操作就是单次或者批量的增加收付款黑名单地址及移除收付款黑名单地址。

四、未增加黑名单时转账

这时解答了第三个问题

  • MetaMask这样的Web3 Wallet可以使用这种ERC20代币吗?
    • 可以

五、对收款人地址增加收款黑名单

检查一下是否维护了黑名单,确实已经是黑名单了。

六、给增加了收款黑名单的地址发起转账

可以发现交易失败,并且可以在区块链浏览器查看到这笔错误交易,错误信息也是在智能合约里定义的”Transfer failed: recipient address is blacklisted”

这时也解答了第四个问题

  • 在智能合约里配置因黑名单造成转账失败的错误提示,可以被查看吗?
    • 可以,都在记录在区块链上,使用区块链浏览器查看。

区块链地址: https://sepolia.etherscan.io/tx/0x85d370c9c9a0feba43930b28a507426728b40bf56adea127d776952050603e78

定义错误描述的代码部分见下:

Leo

区块链系列1 – 如何在以太坊发布一个带图标带官网的ERC20代币

在以太坊上创建并发布一个带有图标和官网链接的ERC20代币,不仅可以提升代币的专业形象,还能增强用户的信任感。


从USDT说起

USDT(Tether)作为最早发行的稳定币之一,USDT 由 Tether Limited Inc. 于 2014 年推出,旨在提供与美元等法定货币挂钩的数字资产。USDT 的价值与美元保持 1:1 的锚定关系,旨在减少加密货币市场的波动性。
USDT 合约地址:https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7


ERC20代币的开发与部署

使用Remix开发环境,结合OpenZeppelin的ERC20标准合约,快速创建了一个名为IOC的代币:

// SPDX-License-Identifier: MIT
// 指定合约的许可证类型为 MIT,表明该合约遵循 MIT 开源许可证。
pragma solidity ^0.8.20;
// 声明 Solidity 编译器的版本要求,确保合约在 0.8.20 版本或更高版本的编译器上编译。

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
// 导入 OpenZeppelin 提供的 ERC20 合约实现,利用其安全且经过审计的标准功能,避免重复造轮子。

contract TeamToken is ERC20 {
    // 定义一个名为 TeamToken 的合约,并继承自 OpenZeppelin 的 ERC20 合约,实现标准的 ERC20 功能。

    string public teamName = "IOC Team";
    // 声明一个公共字符串变量 teamName,用于存储团队名称,任何人都可以读取该值。

    string public teamWebsite = "https://ioc.liangdong.me";
    // 声明一个公共字符串变量 teamWebsite,用于存储团队官网地址,便于用户了解更多信息。

    constructor() ERC20("IOC Team Token", "IOC") {
        // 构造函数,在部署合约时执行。调用父合约 ERC20 的构造函数,设置代币名称为 "IOC Team Token",代币符号为 "IOC"。

        _mint(msg.sender, 238800 * 10 ** 18);
        // 调用 _mint 函数,向部署合约的地址(msg.sender)铸造 238,800 个代币。
        // 由于 ERC20 默认使用 18 位小数,因此实际铸造的单位为 238800 × 10^18。
    }
}

在Environment通过MetaMask关联自己的钱包,同时需要在MetaMask上先切换到主网

通过Remix将合约部署到以太坊主网,通过我的以太坊钱包(MetaMask)liangdong.eth ,部署到主网。

发布后的合约地址:https://etherscan.io/token/0x5541cba0eeed53ae8335b93b7f20ccc453ca03bb

  • 代币基本信息
    IOC Team Token(IOC)是一种ERC-20代币,最大总供应量为238,800个IOC。目前只有1个持有者,且仅有1次转账记录。
  • 市场信息
    文本中未明确给出链上市值和流通供应市值的具体数值。
  • 代币合约地址
    代币合约地址为0x5541cba0eeed53ae8335b93b7f20ccc453ca03bb。

部署到主网的交易见下图,交易地址: https://etherscan.io/tx/0x9ec6974ee204e9e241ed198950a19544d07eaa3abb4bcfe6cd53f409a5412f47

  • 交易费用大概3美元。
    • Transaction Fee:0.0011718135 ETH($3.00)
    • Gas Fee:1.1 Gwei(0.0000000011 ETH)

添加图标和官网链接

为了让IOC代币在Etherscan上展示图标和官网链接,我进行了以下准备:

  1. 官网建设:使用Vibe Coding快速搭建了一个简洁的代币官网:https://ioc.liangdong.me。
  2. 图标设计:利用ChatGPT生成了一个SVG格式的图标:https://ioc.liangdong.me/ioc.svg。

需要注意的是,ERC20标准本身仅包含代币的名称(name)、符号(symbol)和小数位数(decimals)等基本信息,并不包括图标(icon)和官网链接等元数据。这些额外的信息是由区块链浏览器(如Etherscan)提供的展示功能。因此,代币开发者需要主动向这些浏览器提交相关信息,经过审核后才能在代币页面上展示图标和官网链接。

完成以上准备工作后,我在Etherscan的“Update Token Info”页面提交了官网链接和图标,希望能够在区块浏览器上展示。


Etherscan的审核过程

5月18日 10:23提交

5月20日 14:45分收到Etherscan的拒绝电邮

邮件明确表示,Etherscan团队对提交的信息进行审核,并非任何网页和图标都可以随意上传。他们要求代币项目提供足够的信息和详细说明,包括项目介绍、团队信息、社交媒体链接、使用场景、白皮书或文档等。

总结与建议

  • 准备详实的代币信息:Etherscan对项目有明确的要求,建议在提交信息时提供全面、详细且清晰的项目介绍。
  • 官网建设:设计一个清晰、信息全面的代币官网,提升项目的可信度。
  • 图标设计:提供清晰、美观且符合ERC20标准的图标。

通过以上步骤,可以提高代币在Etherscan上展示图标和官网链接的成功率,增强代币的专业形象和用户信任度。

最后,把这个代币展示在自己的钱包里

以MetaMask APP为例,默认打开显示的代币只有ETH和NFT

点击右上角的+号,选择“自定义代币“,输入合约地址:0x5541cba0eeed53ae8335b93b7f20ccc453ca03bb ,就可以在钱包里看到这个代币了,可以看到是238800枚,当然因为这个代币没有流动性,也就没有价值显示,也就是俗称的“空气币”了。

Leo

通过一个简单的角度来理解为何数字货币转账很慢

通过一个简单的角度来理解一下为何比特币、以太坊的转账都很慢,不像微信、支付宝可以做到实时到账。

中心化的模式 的假设前提是“信任”。需要各个使用者相信中央节点的可靠与权威(例如相信支付宝系统的诚实可靠、权威),换来的优势就是近乎瞬间的转账效率。

分布式系统 的假设前提是“互不信任”。则需要在协调各节点达成共识后才能完成转账,这是需要付出昂贵的时间代价的,换来的优势就是账本的可靠性较高且没有中心化风险。

Leo

注册一个姓名eth域名

我也注册了一个eth域名,其实算比较晚了,我自己是不做数字货币投资的,应该是两三年以前为了研究数字货币就买了一点以太币,有好几个eth地址,我是最近才知道有eth域名这个东西,全名叫做ENS,Ethereum Name Service,也就是以太坊名字服务。

对于URL来讲也比较好理解,ENS是为了方便别人对你的eth就行转账操作的,就好比输入IP地址http://8.218.49.106可以访问我的网站,当然是不好记的,所以才有域名这种东西,访问http://liangdong.me 这个就好记多了,所以ENS也是一样,我注册了liangdong.eth来对应我的eth钱包地址0xDb5206169c8c491BC8B17d294DbaFF6644df889B

注册地址是:https://app.ens.domains ,需要使用支持以太坊的浏览器,使用Brave或者使用Chrome加MetaMask(小狐狸)插件,或者使用一些主流的以太坊钱包APP的内置WebView也是可以支持的。

当然了,和注册url域名一样,都是需要每年付费的,注册ENS需要每年付费eth,目前没想到注册liangdong.eth来做什么,先注册着吧,也许几年之后能用得到。

下面是使用imToken生成的收款QR,并不支持使用eth域名来生成,还是标准去钱包地址,也容易理解,QR和域名其实都是为了解决方便输入的问题,QR直接扫码所以使用钱包地址也没问题,如果手动输入的话ENS就派上用场了,输入liangdong.eth比输入0xDb5206169c8c491BC8B17d294DbaFF6644df889B 要方便很多了。

下图是提币操作的截图,支持输入ENS地址,会直接显示出钱包地址,对于P2P转账或个人提币时方便很多,大大减少输错概率。

我建议使用ETH的用户去注册一个属于个人的ENS域名,但是请注意:本文推荐注册一个个人专属的ENS域名,但强烈不建议以任何方式炒作ENS Token。

搜索回忆

输入关键词,找回某个瞬间。