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

如何在Golang中实现UniswapV3 Solidity的位运算逻辑

Solidity uint256 位运算的 Golang 正确实现(对应 UniswapV3 TickBitmap 逻辑)

问题背景

UniswapV3 的 TickBitmap.sol 中有一段位运算代码:

uint256 mask = ~((1 << bitPos) - 1);

尝试用 Golang 实现该逻辑时,得到的结果和 Remix 上的 Solidity 执行结果不一致。

用户原实现代码:

package main

import (
	"fmt"
	"math/big"
)

func main() {
	a := new(big.Int).Exp(big.NewInt(2), big.NewInt(66), nil)
	a.Sub(a, big.NewInt(1))
	b := bitwiseNot(a)
	fmt.Println(b.String())
}

func bitwiseNot(x *big.Int) *big.Int {
	mask := new(big.Int).SetBit(new(big.Int), 256, 1)
	result := new(big.Int).Xor(x, mask)
	return result
}

测试 bitPos=66 时:

  • Remix 输出:115792089237316195423570985008687907853269984665640564039383797031618291433472
  • Golang 原代码输出:115792089237316195423570985008687907853269984665640564039531370984207967846399

问题原因

Solidity 的 uint256 是固定256位无符号整数,按位取反 ~ 只会对低256位进行操作,超出256位的数值会被截断;而 Golang 的 big.Int 是任意精度整数,原代码中用 SetBit(256, 1) 构造的是一个257位的 mask,异或操作会对所有有效位取反,和 Solidity 的逻辑不匹配。

在 Solidity 中,~x(x 为 uint256)等价于 (2^256 - 1) ^ x——因为 uint256 的最大值是 2^256 - 1,按位取反就是和这个最大值做异或运算。

正确实现

package main

import (
	"fmt"
	"math/big"
)

// 构造uint256的最大值:2^256 - 1
var uint256Max = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))

func main() {
	bitPos := big.NewInt(66)
	// 计算 (1 << bitPos) - 1
	shifted := new(big.Int).Lsh(big.NewInt(1), uint(bitPos.Int64()))
	minusOne := new(big.Int).Sub(shifted, big.NewInt(1))
	// 等价于Solidity中的 ~minusOne
	mask := new(big.Int).Xor(minusOne, uint256Max)
	fmt.Println(mask.String())
}

验证结果

运行上述代码,输出结果和 Remix 完全一致:

115792089237316195423570985008687907853269984665640564039383797031618291433472

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:03:36