Huff CLI

简介 虽然多数时候您会在Foundry项目中使用foundry-huff库来编译Huff合约,但编译器自带的CLI提供了一些额外的配置选项和有用的工具 选项 `huffc 0.3.0` 用纯Rust构建的Huff语言编译器 使用格式: `huffc [选项] [路径] [子命令]` 参数: `<路径>` 要编译的合约(一个或多个) 选项: `-a`, `--artifacts` 是否生成产物文件 `-b`, `--bytecode` 生成并记录字节码 `-c`, `--constants <常量>...` 为编译环境覆盖/设置常量 `-d`, `--output-directory <输出目录>` 输出目录 [默认: ./artifacts] `-g`, `--interface [<接口>...]` 为Huff产物文件生成Solidity接口 `-h`, `--help` 打印帮助信息 `-i`, `--inputs <输入参数>...` 构造函数输入参数 `-n`, `--interactive` 交互式输入构造函数参数 `-o`, `--output <输出>` 输出文件路径 `-r`, `--bin-runtime` 生成并记录运行时字节码 `-s`, `--source-path <源路径>` 合约的源路径 [默认: ./contracts] `-v`, `--verbose` 详细输出 `-V`, `--version` 打印版本信息 `-z`, `--optimize` 优化编译 [开发中] 子命令: `help` 打印此信息或给定子命令的帮助信息 `test` 测试子命令 -a 生成产物文件 传递 -a 标志将在 ./artifacts 目录或 -d 标志指定的位置生成产物JSON文件。该JSON文件包含以下信息: File(文件名) Path(路径) Source(源代码) Dependencies(依赖项) Bytecode(字节码) Runtime Bytecode(运行时字节码) Contract ABI(合约ABI) 示例: ...

May 16, 2025 · 2 min · 235 words · Guangyang Zhong

Huff 使用指南

简介 Huff 是一种低级编程语言,专为在以太坊虚拟机(EVM)上开发高性能、优化程度极高的智能合约而设计。Huff 不隐藏 EVM 的内部机制,而是将其编程堆栈暴露给开发者,以便进行手动操作和精细控制 Huff 最初由 Aztec Protocol 团队创建,用于编写 Weierstrudel,这是一个链上椭圆曲线算术库,要求代码极度优化,而 Solidity 和 Yul 都无法满足这种性能需求 虽然 EVM 专家可以使用 Huff 编写适用于生产环境的高效智能合约,但它也可以作为初学者学习 EVM 工作原理的一种方式 👉 Huff 详细使用示例 安装 Huff 编译器是用 Rust 开发的,旨在提供高性能的 Huff 代码编译体验 安装方式与 Foundry 类似 运行命令安装 Huffup: curl -L get.huff.sh | bash 注意事项: 该命令会安装 huffup 可执行文件,但不一定会自动添加到系统路径 如果出现以下错误: huffup: command not found 请执行: source ~/.bashrc # 或者 source ~/.zshrc 或者直接打开一个新的终端窗口 安装完成并在路径中可用后,运行: huffup 即可安装最新稳定版本的 huffc(Huff 编译器) Windows 用户:从源码构建 安装 Rust 工具链: 下载并运行 rustup-init 会在控制台启动安装 如果遇到错误,可能缺少 VS Build Tools,请下载安装 ...

May 16, 2025 · 2 min · 244 words · Guangyang Zhong

Huff 详细使用示例

简介 Huff by Example 旨在详细解释 Huff 语言的各项特性,并通过代码示例说明每个特性的使用方法、使用时机、使用场景以及设计目的。文中的代码片段附有丰富注释,但本节假设读者对 EVM 有一定基础 定义接口 (Defining your Interface) 在 Huff 中定义接口不是必需的步骤,但可以为以下两个目的使用: 作为 __FUNC_SIG 和 __EVENT_HASH 内置函数的参数 生成 Solidity 接口 / 合约 ABI 说明: 函数类型:可以是 view、pure、payable 或 nonpayable 函数接口:仅建议为外部可调用函数定义 事件(Events):可以包含索引值(indexed)和非索引值(non-indexed) 示例: #define function testFunction(uint256, bytes32) view returns (bytes memory) #define event TestEvent(address indexed, uint256) testFunction:定义了一个接受 uint256 和 bytes32 参数的只读函数,返回 bytes 类型 TestEvent:定义了一个事件,包含一个索引地址和一个 uint256 参数 常量 (Constants) 在 Huff 合约中,常量不会存储在合约的 storage 中,而是在编译时即可在合约内调用 常量可以是以下两种类型: 字节(bytes):最大 32 字节 FREE_STORAGE_POINTER:表示合约中未使用的存储槽(storage slot) 使用方法: ...

May 16, 2025 · 7 min · 1410 words · Guangyang Zhong

EIP-2612

摘要 EIP-2612(又称 ERC-2612 / Permit extension for EIP-20)在 EIP-20 基础上新增 permit 接口,允许通过 EIP-712 typed signatures(secp256k1)来更改 allowance,从而无需由 msg.sender 发起 approve 交易 该扩展目的是最小化对现有 ERC-20 生态的入侵,同时解决用户必须持有 ETH 并且需发两笔交易(approve + action)的体验问题 动机 传统 ERC-20 的 approve 以 msg.sender 为准,要求用户必须用 EOA 发起第一次交互(或使用合约钱包)。 当用户要与智能合约交互(例如 deposit、swap 等),往往需要先 approve,再由合约调用 transferFrom:导致至少两笔链上交易、两次 gas 支付。 目标是引入最小、通用且兼容的解决方案,使用户能通过离线签名完成授权,从而可在不持有 ETH 的情况下参与某些操作或把批准与主动作合并成单笔链上交易(例如 depositWithPermit) 注意:合约钱包(contract wallets)也能解决部分问题,但在生态中采纳度较低且需要额外的 UI 适配;permit 方案能在不改动现有 UI 的前提下带来多数好处 规范 合规的实现需要在 ERC-20 基础上实现三项额外函数: function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; function nonces(address owner) external view returns (uint); function DOMAIN_SEPARATOR() external view returns (bytes32); permit 的成功条件: 当前区块时间 block.timestamp 必须 ≤ deadline owner ≠ address(0) nonces[owner](permit 调用前)必须等于消息里包含的 nonce。 v, r, s 必须构成来自 owner 的有效 secp256k1 签名(签名的数据按 EIP-712 的 DOMAIN_SEPARATOR 与 Permit 类型哈希构造) 如果以上任一不满足,permit 必须 revert。成功时应执行: ...

May 1, 2025 · 2 min · 350 words · Guangyang Zhong

Yul 使用指南

简介 Yul(早期称为 JULIA 或 IULIA)是一种中间语言,可编译到多种后端,包括: Ethereum Virtual Machine (EVM) 1.0 EVM 1.5 计划支持的 eWASM 它旨在作为这些平台的通用标准。Yul 已经可以在 Solidity 中作为 内联汇编 使用,未来 Solidity 编译器甚至可能将 Yul 用作默认的中间语言。Yul 的设计也使得为其构建高级优化器变得容易 核心特性: 核心组件 函数(function) 代码块(block) 变量(variable) 字面量(literal) 循环(for) 条件语句(if / switch) 表达式与变量赋值 强类型系统 变量和字面量必须带类型前缀 支持类型:bool, u8, s8, u32, s32, u64, s64, u128, s128, u256, s256 操作符与内置函数 Yul 本身不提供操作符 对于 EVM,操作码(opcode)作为内置函数提供 如果后端平台不同,可以重新实现这些函数 示例: 递归实现 { function power(base:u256, exponent:u256) -> result:u256 { switch exponent case 0:u256 { result := 1:u256 } case 1:u256 { result := base } default: { result := power(mul(base, base), div(exponent, 2:u256)) switch mod(exponent, 2:u256) case 1:u256 { result := mul(base, result) } } } } 循环实现 { function power(base:u256, exponent:u256) -> result:u256 { result := 1:u256 for { let i := 0:u256 } lt(i, exponent) { i := add(i, 1:u256) } { result := mul(result, base) } } } 注:循环实现依赖 EVM 的 lt 和 add 操作码。 ...

February 16, 2025 · 8 min · 1552 words · Guangyang Zhong

EIP-2718

摘要 TransactionType || TransactionPayload 是一个有效的交易格式,TransactionType || ReceiptPayload 是一个有效的交易收据格式,其中: TransactionType 标识交易格式 *Payload 是交易/收据内容,由未来的EIP定义 动机 过去,当我们想要添加新的交易类型时,必须确保它们与所有其他交易向后兼容,这意味着只能根据编码后的有效载荷来区分它们,并且不可能存在匹配两种类型的交易。这在EIP-155中可以看到,新值被位打包到其中一个编码字段中 当前有多个提案正在讨论中,它们定义了新的交易类型,例如: 允许EOA账户直接在其上下文中执行代码的交易 允许msg.sender以外的人支付gas的交易 与第1层多签交易相关的提案 所有这些都需要以相互兼容的方式定义,这很快成为EIP作者和客户端的负担,因为他们现在必须遵循复杂的规则来区分交易类型 通过引入信封交易类型,我们只需要确保与现有交易的向后兼容性,之后我们只需要解决确保TransactionType之间没有编号冲突这个更简单的问题 规范 定义 || 是字节/字节数组连接运算符 交易 从FORK_BLOCK_NUMBER开始,区块头中的交易根必须是patriciaTrie(rlp(Index) => Transaction)的根哈希,其中: Index 是此交易在区块中的索引 Transaction 是以下之一: TransactionType || TransactionPayload LegacyTransaction TransactionType 是一个在0到0x7f之间的无符号8位正整数,表示交易类型 TransactionPayload 是一个不透明的字节数组,其解释取决于TransactionType并由未来的EIP定义 LegacyTransaction 是rlp([nonce, gasPrice, gasLimit, to, value, data, v, r, s]) 所有未来交易类型的签名应该将TransactionType作为签名数据的第一个字节。这样我们就不必担心一种交易类型的签名被用作另一种交易类型的签名 收据 从FORK_BLOCK_NUMBER开始,区块头中的收据根必须是patriciaTrie(rlp(Index) => Receipt)的根哈希,其中: Index 是此收据对应的交易在区块中的索引 Receipt 是以下之一: TransactionType || ReceiptPayload LegacyReceipt TransactionType 是一个在0到0x7f之间的无符号8位正整数,表示交易类型 ReceiptPayload 是一个不透明的字节数组,其解释取决于TransactionType并由未来的EIP定义 LegacyReceipt 是rlp([status, cumulativeGasUsed, logsBloom, logs]) 收据的TransactionType必须与具有匹配Index的交易的TransactionType相匹配 ...

January 1, 2025 · 1 min · 103 words · Guangyang Zhong

EIP-20

摘要 本标准允许在智能合约中实现一个标准化的代币API。它提供了转账代币的基本功能,并允许批准代币以便可以被其他链上第三方花费。 动机 一个标准化的接口允许以太坊上的任何代币被其他应用程序重复使用:从钱包到去中心化交易所 规范 代币 方法 注意: 以下规范使用 Solidity 0.4.17(或更高版本)的语法 调用者必须处理返回 false(bool success)的情况。调用者绝不能假定 >false 永远不会被返回! name 功能:返回代币的名称 - 例如 "MyToken" 可选性:此方法可用于提高可用性,但接口和其他合约绝不能期望这些值一定存在 function name() public view returns (string) symbol 功能:返回代币的符号。例如 "HIX" 可选性:此方法可用于提高可用性,但接口和其他合约绝不能期望这些值一定存在 function symbol() public view returns (string) decimals 功能:返回代币使用的小数位数 - 例如 8,表示将代币数量除以 100000000 以获得其用户表示形式 可选性:此方法可用于提高可用性,但接口和其他合约绝不能期望这些值一定存在 function decimals() public view returns (uint8) totalSupply 功能:返回代币总供应量 function totalSupply() public view returns (uint256) balanceOf 功能:返回地址 _owner 的账户余额 function balanceOf(address _owner) public view returns (uint256 balance) transfer ...

August 20, 2024 · 1 min · 205 words · Guangyang Zhong

EIP-712

摘要 这是一个用于对类型化结构化数据(而不仅仅是字节串)进行哈希和签名的标准。它包括: 理论框架:用于确保编码函数的正确性 结构化数据规范:与 Solidity 结构体类似且兼容 安全哈希算法:用于这些结构体的实例 安全纳入机制:将这些实例纳入可签名消息集合 可扩展的域分离机制 新的 RPC 调用:eth_signTypedData EVM 中哈希算法的优化实现(可选) 不包含重放攻击保护 动机 如果只关心字节串,数据签名是一个已解决的问题。但在现实世界中,我们关心的是复杂且有意义的消息。对结构化数据进行哈希处理并非易事,错误会导致系统安全属性的丧失 因此,“不要自己发明加密算法”(don‘t roll your own crypto)的格言在此适用。我们需要使用经过同行评审、充分测试的标准方法。本 EIP 旨在成为这个标准 本 EIP 旨在提高链下消息签名在链上使用的可用性。链下消息签名因其节省 Gas 和减少链上交易数量而被广泛采用。目前,已签名的消息对用户来说是一个不透明的十六进制字符串,几乎没有关于消息的上下文信息 本提案概述了一种编码数据及其结构的方案,允许在签名时向用户显示信息以供验证 本协议提出前的签名样式: 本协议提出后的签名样式 规范 明白,你是要 Markdown 语法的笔记,但内容保持学术/规范风格,不要花里胡哨。下面是 纯 Markdown、可直接粘到笔记里的版本。 可签名消息集合的扩展 以太坊原本支持对以下两类数据进行签名: 交易(𝕋) 任意字节串(𝔹⁸ⁿ) EIP-712 引入了结构化数据(𝕊)作为新的可签名对象,因此可签名消息集合扩展为: 𝕋 ∪ 𝔹⁸ⁿ ∪ 𝕊 不同类型消息的编码规则 为了便于哈希与签名,不同类型的消息在签名前会被编码为字节串。 1. 交易(𝕋) encode(transaction) = RLP_encode(transaction) 交易签名直接对交易的 RLP 编码结果进行签名,这是以太坊最基础的交易签名方式,用于转账和合约调用。 2. 普通字节串消息(𝔹⁸ⁿ) encode(message) = "\x19Ethereum Signed Message:\n" ‖ len(message) ‖ message 其中 len(message) 是消息字节长度的非零填充 ASCII 十进制编码 该编码方式对应 eth_sign / personal_sign,通过加入固定前缀,防止普通消息被误解释为交易数据 ...

August 20, 2024 · 4 min · 708 words · Guangyang Zhong