You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用汇编实现基于chainId和合约地址生成URL以降低Gas?

低Gas开销的汇编实现方案

下面是完全通过内联汇编实现的URL生成函数,无需依赖OpenZeppelin的Strings.sol,部署Gas成本仅增加数千单位:

function url() public view returns (string memory) {
    uint256 chainId = block.chainid;
    address self = address(this);

    // 计算最终字符串长度:前缀(29) + chainId十进制位数 + 分隔符(1) + 地址十六进制(42)
    uint256 chainIdLen = _getDecimalLength(chainId);
    string memory result = new string(29 + chainIdLen + 1 + 42);

    assembly {
        // 指向字符串内容的起始位置(字符串结构体首字节是长度,偏移0x20才是内容)
        let ptr := add(result, 0x20)

        // 写入固定前缀 "https://website.com/token/"
        // 前缀的十六进制表示:0x68747470733a2f2f776562736974652e636f6d2f746f6b656e2f
        mstore(ptr, 0x68747470733a2f2f776562736974652e636f6d2f746f6b656e2f)
        ptr := add(ptr, 29) // 前缀实际长度29,移动指针到下一个写入位置

        // 处理chainId的十进制转字符串
        let num := chainId
        let tempPtr := add(ptr, 0x40) // 临时存储反转的数字字符
        let len := chainIdLen

        // 将数字按位反转存入临时内存
        for { let i := 0 } lt(i, len) { i := add(i, 1) } {
            mstore8(add(tempPtr, i), add(mod(num, 10), 0x30)) // 取余数转ASCII
            num := div(num, 10)
        }

        // 将反转的字符写回目标位置
        for { let i := 0 } lt(i, len) { i := add(i, 1) } {
            mstore8(add(ptr, i), mload8(add(tempPtr, sub(len, i))))
        }
        ptr := add(ptr, len)

        // 写入分隔符 "/"
        mstore8(ptr, 0x2F)
        ptr := add(ptr, 1)

        // 写入地址的十六进制字符串(带0x前缀)
        mstore8(ptr, 0x30) // '0'
        mstore8(add(ptr, 1), 0x78) // 'x'
        ptr := add(ptr, 2)

        let addr := self
        // 处理地址的每个字节,转两位十六进制字符
        for { let i := 0 } lt(i, 20) { i := add(i, 1) } {
            let byteVal := and(shr(mul(sub(19, i), 8), addr), 0xFF)
            // 高4位转ASCII
            let highNibble := shr(4, byteVal)
            mstore8(add(ptr, mul(i, 2)), add(highNibble, lt(highNibble, 10) ? 0x30 : 0x57))
            // 低4位转ASCII
            let lowNibble := and(byteVal, 0x0F)
            mstore8(add(ptr, add(mul(i, 2), 1)), add(lowNibble, lt(lowNibble, 10) ? 0x30 : 0x57))
        }
    }

    return result;
}

// 计算uint256的十进制位数
function _getDecimalLength(uint256 num) internal pure returns (uint256) {
    if (num == 0) return 1;
    uint256 length = 0;
    while (num > 0) {
        length++;
        num /= 10;
    }
    return length;
}

核心优化点:

  • 直接操作内存写入固定前缀,避免字符串拼接的Gas消耗
  • 手动实现十进制/十六进制转ASCII的逻辑,完全绕过第三方库的额外代码
  • 所有内存操作通过汇编完成,最小化Gas开销

内容的提问来源于stack exchange,提问作者Cloudronaut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 02:35:14