Hello World - 区块链
type: channel
link: https://wlwl.host/index.php/category/blockchain
description: 区块链、以太坊、智能合约
items: 以太坊提案7702
items: 使用Anchor构建Solana程序
items: Solana和Ethereum对比
items: 区块链 重放攻击
items: Solidity 错误处理
items: 智能合约代理
items: Permit 代币签名批准
items: 虚拟机 抽象
items: Ton链 Telegram小程序
items: hardhat 可升级合约

以太坊提案7702
type: item
date: 2025-06-07T15:05:00+00:00
description: 以太坊改进提案EIP-7702：EOA账户代码委托EIP-7702是一项以太坊改进提案，它允许外部拥有账户(EOA)将其代码委托给另一个合约地址，从而使EOA能够像智能合约一样执行代码。这项提案为以太坊生态系统带来了新的可能性，让用户账户能够拥有更多的功能性。EIP-7702的核心概念EIP-7702引入了一种新的交易类型（0x4），它扩展了现有的EIP-1559交易格式，增加了一个authorization_list字段。这个字段包含了授权信息，允许EOA账户将其代码委托给指定的合约地址。授权列表结构授权信息的结构包含以下字段：chain_id: 链IDaddress: 委托的合约地址nonce: 账户的nonce值y_parity, r, s: 签名信息Gas成本EIP-7702的gas成本计算遵循以下规则：基础gas成本继承自EIP-1559授权列表中的每个授权项需要额外支付25000gas如果在授权时EOA账户已经在access_list中，则返还一半的gas代码委托机制当EOA账户委托其代码给另一个合约地址时：EOA账户的代码会被设置为委托指示器：0xef0100 + 委托合约地址当对EOA账户进行call调用时，会加载委托合约的代码作为EOA账户的代码执行CODESIZE和CODECOPY指令使用的是委托合约的代码EXTCODESIZE和EXTCODECOPY指令使用的是EOA账户的代码（23字节）特殊情况处理EIP-7702对一些特殊情况有明确的处理规则：如果委托地址为零地址，则EOA账户的代码会被置空如果委托形成循环（委托指示器指向另一个委托），则使用第一个委托的代码如果委托地址为预编译合约，则相当于使用空代码，不会调用预编译合约函数交易执行流程EIP-7702交易的执行流程如下：交易检查和gas预付发送账户的nonce增加处理授权列表（在交易开始执行之前，增加EOA的nonce，设置EOA账户的代码为委托指示器）执行交易的call调用需要注意的是：如果设置EOA账户代码的交易执行失败（开始执行前就已经设置code了），则已经成功设置的账户代码不会被撤销如果处理某个授权时失败，则停止处理当前的授权，并继续处理下一个授权处理失败的授权不会退还gas费实际应用场景EIP-7702为以太坊生态系统带来了多种新的应用场景：1. EOA账户功能扩展通过代码委托，EOA账户可以拥有智能合约的功能，同时保持EOA的特性。这使得用户可以在不创建新合约的情况下，为自己的账户添加自定义逻辑。2. 账户抽象EIP-7702为账户抽象提供了新的可能性，允许用户自定义其账户的行为，例如实现多签名验证、社交恢复等功能。3. 资产托管在正确设置委托代码的之后，允许其他账户在授权的情况下代表EOA执行资产转账等操作。技术实现细节EIP-7702的实现涉及以太坊客户端的多个组件：交易处理：增加新的交易类型，并在交易执行前处理授权列表（nonce增加之后）代码加载：修改EVM以支持代码委托机制，并在call类调用时加载委托合约的代码签名验证是EIP-7702的关键部分，每个委托授权都需要对应的EOA亲自签署，授权信息的签名消息格式为：msg = (0x05 || rlp([chain_id, address, nonce]))而交易的签名消息格式为：msg = (0x04 || rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list, authorization_list]))参考链接提案标准

使用Anchor构建Solana程序
type: item
date: 2025-05-04T13:13:00+00:00
description: 什么是Anchor？Rust通常被描述为Solana程序开发的通用语言。但更准确地说，Anchor才是真正的通用框架，因为大多数Rust开发都使用这个框架。Anchor是一个有主见且强大的框架，旨在快速构建安全的Solana程序。它通过减少账户（反）序列化和指令数据等领域的样板代码，进行必要的安全检查，自动生成客户端库，并提供广泛的测试环境，从而简化开发过程。本文将探讨如何开发Anchor程序。它涵盖了安装Anchor、使用Solana Playground以及创建、构建和部署一个简单的Hello, World!程序。然后，我们将深入探讨Anchor如何通过检查IDL、宏、Anchor程序的结构、账户类型和约束条件以及错误处理来简化开发过程。我们还将简要介绍跨程序调用和程序派生地址。本文将提供你开始使用Anchor所需的一切知识。前提知识本文假设你已了解Solana的编程模型。如果你是Solana开发新手，我建议阅读我之前的博客文章《Solana编程模型：Solana开发入门》。如果你是Rust新手，不必担心 - 开始Anchor开发不需要高级知识。Anchor文档指出，开发者只需熟悉Rust的基础知识（即Rust书籍的前九章）。我建议观看《Rust生存指南》，了解Rust编程概念的基本要点。了解Rust的内存、所有权和借用规则也至关重要。为了减轻学习曲线，我建议新接触低级编程语言的开发者复习Rust资源往往跳过的不同系统编程特定概念。例如，我建议了解变量大小、指针和内存泄漏等主题。我还推荐《通过示例学Rust》和我的仓库，其中包含用Rust编写的各种数据结构和算法示例。想使用TypeScript代替吗？了解如何使用Poseidon框架用TypeScript编写Solana程序，将TypeScript转译为Rust并生成有效的Anchor程序。本文专注于Anchor开发，仅限于Anchor开发。我们不会介绍如何用原生Rust开发程序，本文也不假设你了解这方面的知识。此外，本文不会涵盖Anchor的客户端开发 - 我们将在未来的文章中介绍如何通过TypeScript测试和与Anchor程序交互。话不多说，让我们开始使用Anchor吧！安装Anchor设置Anchor涉及几个简单的步骤，安装必要的工具和包。本节介绍如何安装这些工具和包（即Rust、Solana工具套件、Yarn和Anchor版本管理器）。安装RustRust可以从官方Rust网站安装，或通过命令行安装：curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh安装Solana工具套件Anchor还需要Solana工具套件。最新版本可以使用以下命令为macOS和Linux安装：sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"可以将 stable 替换为与您所需版本的软件版本匹配的发布标签（例如 v2.0.3），或者使用以下三个符号通道名称之一： stable、 beta 或 edge。安装后，运行solana --version确认已安装所需版本的solana。安装AVMAnchor 版本管理器 (AVM) 允许您在系统上安装和管理不同的 Anchor 版本，并在未来轻松更新 Anchor 版本。使用以下命令安装AVM：cargo install --git https://github.com/coral-xyz/anchor avm --force使用AVM安装AnchorAnchor文档建议通过Anchor版本管理器（AVM）安装Anchor。AVM简化了管理和选择anchor-cli二进制文件的多个安装。这可能是生成可验证构建或在不同程序之间使用替代版本所必需的。使用Solana PlaygroundSolana Playground是一个基于Web的IDE，允许开发者在浏览器中编写、构建和部署Solana程序。它是一个强大的工具，特别是对于那些不想在本地设置开发环境的开发者。创建、构建和部署Hello, World!程序这是因为它们的简单性，各种技能水平的开发者都能理解它们。这些程序还阐明了新编程模型的基本结构和语法，而不引入复杂的逻辑或函数。它已经迅速成为编码中相当标准的初学者程序，所以我们自然要为Anchor编写一个。本节介绍如何使用本地Anchor设置以及Solana Playground构建和部署Hello, World!程序。declare_id!宏为程序设置公钥。对于本地开发，用于设置程序的anchor init命令将在target/deploy目录中生成一个密钥对，并填充此宏。Solana Playgro…

Solana和Ethereum对比
type: item
date: 2025-04-26T12:40:00+00:00
description: Solana的重要概念：共识机制、账户模型、程序、交易、指令等等一、共识机制Solana的创新共识机制Proof of History (PoH)PoH是Solana区块链的核心创新之一，它为区块链提供了一个去中心化的时间源。PoH本质上是一个高频可验证延迟函数 (VDF)，它能够创建历史记录，证明某个事件发生在特定时刻之前或之后。PoH是一种创新的时间记录机制，通过加密散列函数生成一个可验证的时间顺序，使得区块链中的事件可以按时间线性顺序排列。这减少了节点之间的时间同步需求，使得节点能够迅速达成共识，而无需等待整个网络确认。PoH工作流程：使用哈希函数将事件序列化，每个哈希值都依赖于前一个哈希值通过计数器记录哈希计算的次数，可以推断出时间的流逝当需要记录事件时，将事件数据插入到PoH序列中，后续所有哈希值都会因此变化这种机制确保了事件的顺序性和时间戳的可验证性Proof of Stake (PoS)验证者需要抵押一定数量的SOL代币，持有更多代币的验证者有更高的概率被选中生成区块。PoS提供了经济激励，确保验证者行为诚实。PoH与PoS的结合：PoH确保区块的时间戳和顺序，PoS则确保网络的安全性和抗攻击性，两者结合使得网络能够达到每秒数千笔交易处理速度。 虽然权益证明(PoS)确保网络中达成共识，但Solana将历史证明(PoH)纳入其PoS共识机制中，从而实现连续区块生产的同步。以太坊从PoW到PoS的转变以太坊 2.0 的升级（The Merge）将共识机制从能源密集的 PoW 转为 PoS，大幅降低了能耗。验证者通过锁定 ETH 参与共识，取代了矿工的角色，提升了网络的安全性和可持续性。Solana与以太坊共识机制的比较在非分区状态下，Solana网络中始终都只有一个领导者。每个验证器节点和领导者拥有相同的硬件能力，且验证器可以被选举为领导者，这种选举是基于PoS的。这种网络设计，在出块速度上相比于以太坊将会有大幅度提升，但是，在去中心化程度上，却不如以太坊。二、交易处理能力Solana的并行处理通过将交易分解为多个子集，利用不同的验证节点并行处理，提高了吞吐量。Solana的架构支持高达每秒数千笔交易，平均出块时间为400毫秒，平均每秒2000+笔交易，在高负载时保持较低的交易费用。低延迟和低费用Solana的架构设计使其能够快速确认交易，通常在一秒以内完成。即使在高负载下，交易费用仍保持低廉，适合需要高频交易的应用。海湾流（Gulf Stream）和海平面（Sealevel）技术Solana在技术底层架构上，不得不提到的两个技术层面一个就是海湾流（Gulf Stream)以及海平面（Sealvel)，这两个技术相辅相成，是支撑Solana成为新的世界级公链的两大支柱。海湾流(Gulf Stream)：无内存交易转发协议，解决了传统区块链内存池（MemPool）造成的网络瓶颈问题海平面(Sealevel)：允许智能合约并行运行的技术，大幅提高了交易处理效率以太坊的串行执行以太坊的智能合约在虚拟机（EVM）中按顺序执行，每笔交易必须等待前一笔完成才能开始。虽然这种方式确保了状态的一致性，但也限制了以太坊吞吐量长期维持在每秒15笔～30笔，以牺牲性能换来安全性和一致性。Layer 2和RollupLayer 2解决方案通过将大量交易在链下处理，然后将结果提交到主链，显著提高了交易速度和降低了成本。Rollup是其中一种常见的技术，能够将数百笔交易合并为一个批次，能够将燃料费减少多达100倍。三、交易费用（Gas费）Solana的交易费用机制Solana的交易费用是根据交易的复杂度和大小动态计算的，这意味着，交易费用会根据交易的执行成本而变化，而不是根据网络上的交易量变化。Solana的平均交易费用通常低于0.01美元，平均为0.00025美元，这使得进行小额交易更具成本效益。基础手续费结构基础手续费目前设定为每个签名0.000005 SOL（5,000 lamports），构成了交易成本的基础。这是由一个地址支付的费用，以便获得使用网络资源的权利。这是一个一次性的总费用，无论实际使用多少资源来执行交易（或者交易是否执行），都需要预先支付给网络。计算单元Solana交易会预先请求指定数量的计算单元（CUs），如果超出这个数量，交易将失败。这意味着开发者目前几乎没有任何财务激励来最小化计算单元的请求。以太坊的交易费用以太坊的交易费用因网络拥堵而波动，这是一种纯粹的市场机制，网络中交易拥堵情况下你的交易要想被确认，就需要支付高昂的手续费。目前一笔转账交易的手续费大概在 1 ～ 10 美元左右。四、智能合约Solana的程序模型Solana中一切皆账户，它的智能合约（Solana 中称之为程序program）也是账户，但细分为…

区块链 重放攻击
type: item
date: 2025-04-20T11:26:00+00:00
description: 引言在区块链技术的快速发展中，安全问题始终是一个不可忽视的关键因素。其中，重放攻击作为一种常见的攻击手段，对区块链交易的安全构成了重大威胁。本文将深入探讨区块链重放攻击的概念、常见类型以及有效的防护措施，帮助开发者和用户更好地理解并防范这类安全风险。什么是区块链重放攻击？重放攻击是一种攻击手段，攻击者通过拦截并操作网络上的数据传输来实现。在区块链领域，重放攻击指攻击者通过操控并重用有效交易来获取不当利益。具体而言，攻击者可以将交易复制到另一个链上，或者复制、修改签名，使其通过验证检查，从而实现非法目的。在理解重放攻击之前，建议先了解以下基础知识：以太坊中的签名和认证机制ECDSA密钥生成、签名和验证过程EIP-191和EIP-712签名标准五种常见的区块链重放攻击类型1. 缺失应用程序随机数(Nonce)重放攻击攻击原理签名是区块链技术中提供加密认证的关键机制，作为唯一的"指纹"构成区块链交易的基础。在这种攻击中，由于缺少应用程序随机数(Nonce)，攻击者可以重复使用之前的有效签名进行欺诈交易。攻击流程签名者签署一个不包含随机数的消息攻击者从之前的交易中拦截并复制签名攻击者重新利用此签名发送新的交易防护措施实现应用程序随机数是防止这类攻击的有效方法。在智能合约中，可以通过以下方式实现：// 在合约中添加随机数映射 mapping (address => uint256) public nonces; // 在签名验证过程中检查随机数 function verifySignature(address signer, uint256 nonce, bytes memory signature) internal { // 验证随机数是否递增 require(nonce == nonces[signer], "Invalid nonce"); // 验证签名... // 更新随机数 nonces[signer]++; }2. 硬分叉重放攻击攻击原理硬分叉是对区块链协议的重大且不向后兼容的更改，导致创建两个独立账本：原始账本和新分叉账本。当两个账本共享相同的交易和地址格式时，就会出现重放攻击的可能性。攻击流程区块链发生硬分叉，形成两条独立的链攻击者拦截一条链上的合法交易攻击者将相同的交易重放到另一条链上防护措施实现链ID验证：在交易签名中包含链ID，确保交易只能在特定链上有效使用不同的地址格式：为新链设计不同的地址格式，防止交易在不同链间重放实现重放保护机制：在硬分叉时添加特殊的交易字段，使交易只能在一条链上有效3. 跨链重放攻击攻击原理随着区块链生态系统的扩展，不同链之间的互操作性增强，这也带来了跨链重放攻击的风险。攻击者可以将在一条链上有效的交易重放到另一条链上。攻击流程用户在链A上签署交易攻击者截获该交易攻击者将相同的交易提交到链B上防护措施在签名消息中包含链标识符实现跨链通信协议，确保交易的唯一性使用不同的签名算法或参数4. 签名可塑性重放攻击攻击原理签名可塑性是指在不改变签名有效性的情况下，可以修改签名的特性。攻击者可以利用这一特性，修改交易签名并重新广播，导致同一交易被多次执行。攻击流程用户发送有效交易攻击者修改签名（保持其有效性）攻击者重新广播修改后的交易防护措施使用标准化的签名格式（如低S值）实现交易ID计算方法，使其不受签名可塑性影响在智能合约中实现额外的验证机制5. 密码学随机数重用重放攻击攻击原理在ECDSA等签名算法中，如果在不同消息的签名过程中重用了相同的密码学随机数(k)，攻击者可以计算出私钥，从而完全控制账户。攻击流程签名者在两个不同消息的签名中使用相同的随机数k攻击者获取这两个签名攻击者通过数学计算推导出私钥防护措施使用确定性签名算法（如RFC 6979）确保每次签名使用不同的随机数使用硬件安全模块(HSM)进行签名操作综合防护策略1. 实现完整的签名验证在智能合约中实现严格的签名验证机制，包括：验证签名者地址检查消息内容完整性验证随机数的有效性和唯一性检查签名的有效期2. 使用标准化的签名方案采用经过验证的签名标准，如EIP-712，它提供了结构化数据的签名方案，使签名更安全、更易于验证。3. 实现交易唯一性保障通过以下方式确保交易的唯一性：在交易中包含时间戳使用递增的随机数添加唯一的交易标识符4. 定期安全审计对智能合约和区块链应用进行定期安全审计，特别关注与签名验证和交易处理相关的代码。实际案例分析KYCRegistry合约中的重放攻击漏洞以下是一个存在重放攻击漏洞的KYCRegistry合约示例（点击查看更多详情）：function addKYCAddressViaSignature(uint8 kycRequirementGroup, address user, uint256 deadli…

Solidity 错误处理
type: item
date: 2025-03-16T14:52:00+00:00
description: 引言本文详细描述了调用智能合约时可能发生的各种错误，以及Solidity的Try/Catch块如何响应（或未能响应）这些错误。要理解Solidity中的Try/Catch如何工作，我们必须了解当低级调用失败时返回的数据。编译器决定了这种行为，而不是以太坊虚拟机。因此，用其他语言或汇编编写的合约不一定会遵循这里解释的所有错误格式。低级调用失败的情况当对外部合约的低级调用失败时，它返回一个布尔值false。这个false表示调用未成功执行。调用在以下情况下可能返回false：被调用的合约回滚（revert）被调用的合约执行非法操作（如除以零或访问越界数组索引）被调用的合约耗尽所有gas在以下部分中，我们将检查可能导致低级调用返回 false 的情况，以及它们可能提供的任何返回数据。然后我们将探讨Try/Catch如何处理（或未能处理）每种情况。第1部分：在回滚时返回什么内容1. 如果使用了没有错误字符串的revert，会返回什么？使用revert的最简单方法是不提供回滚原因。contract ContractA { function mint() external pure { revert(); } }如果我们部署上述合约（ContractA）并从另一个合约（ContractB）进行低级调用mint()函数，如下所示：// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; import "hardhat/console.sol"; contract ContractB { function call_failure(address contractAAddress) external { (, bytes memory err) = contractAAddress.call( abi.encodeWithSignature("mint()") ); console.logBytes(err); } }revert()错误将被触发，不会返回任何数据。错误返回的数据是0x，这只是没有附带数据的十六进制表示。2. 从带有错误字符串的revert中返回什么？另一种使用revert的方法是提供一个字符串消息。这有助于识别合约中交易失败的原因。让我们触发一个带有字符串的回滚，看看返回了什么：contract ContractB { function mint() external pure { revert("Unauthorized"); } }调用合约将是：import "hardhat/console.sol"; contract ContractA { function call_failure(address contractBAddress) external { (, bytes memory err) = contractBAddress.call( abi.encodeWithSignature("mint()") ); console.logBytes(err); // just so we can see the error data } }当revert带有字符串参数触发时，它会将 Error 函数Error(string)的ABI编码返回给调用者。我们回滚的返回数据将是函数调用的ABI编码Error("Unauthorized")。在这种情况下，它将具有Error(string)函数的函数选择器，字符串的偏移量，长度和字符串内容的十六进制编码。让我们进一步解释输出：选择器08c379a0是keccak256("Error(string)")的前四个字节，其中string指的是原因字符串。接下来的96个字节（3个32字节）是字符串Unauthorized的ABI编码前32个字节是字符串长度位置的偏移量第二个32个字节是字符串的长度（12个字节以十六进制表示为c）字符串Unauthorized的实际内容以UTF-8编码为字节556e617574686f72697a65643. 从自定义revert中返回什么？Solidity0.8.4引入了错误类型，可以与revert语句一起使用，以创建既可读又节省gas的自定义错误。要创建自定义错误类型，你将使用关键字error来定义错误，类似于定义事件：error Unauthorized();如果需要强调错误信息的一些细节，你也可以定义带有参数的自定义错误：error CustomError(arg1, arg2, etc)。error Unauthorized(address caller);没有参数的自定义revert让我们比较一个带参数的自定义回滚与一个不带参数的例子：pragma solid…

智能合约代理
type: item
date: 2025-02-22T13:43:00+00:00
description: 智能合约代理（Proxy）引言在区块链开发中，智能合约一旦部署到链上就无法更改，这种不可变性虽然提供了安全保障，但也带来了灵活性的挑战。代理模式应运而生，成为解决这一问题的关键技术。基础概念什么是代理模式？代理（Proxy）本身并不是固有可升级的，但它是几乎所有可升级合约模式的基础。对代理合约的调用会通过 delegatecall 转发到实现合约（也称为逻辑合约）。这种机制允许合约逻辑与存储分离，从而实现合约的可升级性。关键术语代理合约（Proxy Contract）：用户直接交互的合约，负责转发调用并存储数据实现合约/逻辑合约（Implementation/Logic Contract）：包含实际业务逻辑的合约delegatecall：特殊的调用方式，在调用者的上下文中执行被调用合约的代码存储槽（Storage Slot）：合约存储中的特定位置，用于存储变量基本代理模式EIP-1167最小代理EIP-1167 标准于 2018 年 6 月创建，旨在标准化以简单、便宜且不可变的方式克隆合约功能。该标准包含了针对代理合约优化的最小字节码重定向实现。通常与工厂模式一起使用。// 最小代理合约示例 bytes memory bytecode = hex"363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3"; // 其中 "bebebebe..." 需要替换为实际的实现合约地址 bytecode = abi.encodePacked( bytecode[:20], implementationAddress, bytecode[40:] );代码解读特点：实现地址：在代理合约中是不可变的升级逻辑：纯代理合约中没有可升级性合约验证：可与Etherscan和其他区块浏览器配合使用。优点：部署成本低缺点：每次调用会增加一次 delegatecall 的费用无法升级实现合约应用场景：当需要部署多个代码基本相同的合约时非常有用实际应用：Uniswap V1 AMM 池已知漏洞：实现合约中不允许使用 delegatecall 和 selfdestruct可初始化代理初始化的挑战使用代理的主要好处之一是只需部署一次实现合约，然后可以部署多个指向它的代理合约。然而，缺点是无法在创建新代理时使用已经部署的实现合约中的构造函数。正如开发者常问的："但我们该如何在没有 constructor() 的情况下工作？"初始化函数解决方案是使用 initialize() 函数来设置初始存储值：uint8 private _initialized; function initialize() external { require(msg.sender == owner); require(_initialized < 1); _initialized = 1; // 设置一些状态变量 // 做初始化工作 }优点：允许在新代理部署时设置初始存储缺点：易受与初始化相关的攻击，尤其是未初始化的代理应用场景：任何需要在代理合约部署时设置存储的代理，适用于大多数代理类型，包括TPP和UUPS。可升级代理基本可升级代理可升级代理类似于简单代理，只不过实现合约地址是可设置的，并保存在代理合约中。代理合约还包含授权的升级功能。特点：实现地址：位于代理存储中升级逻辑：位于代理合约中合约验证：根据具体实现，可能无法与像和Etherscan这样的区块浏览器配合使用优点：通过使用代理降低部署成本实现合约可以升级缺点：易受存储和功能冲突的影响安全性不如当前同类产品。每次调用都要承担来自代理的 delegatecall 费用应用场景：这种基本风格已不再广泛使用。已知漏洞：实现中不允许使用 delegatecall 和 selfdestruct未初始化的代理存储冲突功能冲突EIP-1967 可升级代理这类似于基本可升级代理，但通过使用无结构存储模式减少存储冲突的风险。它不将实现合约地址存储在槽0或任何其他标准存储槽中。相反，地址存储在预先商定的槽中。例如，OpenZeppelin合约使用字符串"eip1967.proxy.implementation"的keccak256哈希值减去 1。由于这个槽广泛使用，区块浏览器可以识别并处理代理的使用。减去1提供了额外的安全性，因为没有它，存储槽有一个已知的预映像，但在减去1之后，预映像是未知的。对于已知的预映像，存储槽可能会通过映射被覆盖，例如，其中存储槽的键是通过keccak256哈希确定的。EIP-1967还指定了一个用于管理员存储（auth）的槽，以及Beacon代理模式。特点：实现地址：位于代理合约中的唯一存储槽升级逻…

Permit 代币签名批准
type: item
date: 2025-01-04T09:58:00+00:00
description: 在以太坊生态系统中，ERC-20代币是最常见的代币标准之一。它定义了代币的基本接口，包括转账、余额查询等功能。然而，随着 DeFi（去中心化金融）的快速发展，传统的ERC-20代币在某些场景下显得不够灵活。特别是在需要用户多次授权合约操作时，用户需要多次签名并支付Gas费用，这不仅增加了用户的操作成本，还降低了用户体验。为了解决这个问题，EIP-2612提出了permit功能，允许用户通过链下签名的方式授权合约操作，从而减少链上交易次数和Gas消耗。本文将详细介绍permit功能的实现原理、使用场景以及如何在智能合约中集成这一功能。一、什么是Permitpermit是ERC-20代币的一个扩展功能，它允许用户通过链下签名的方式授权第三方合约或地址使用其代币。与传统的approve方法不同，permit不需要用户发送链上交易，而是通过签名的方式在链下完成授权。合约可以通过验证签名来获取用户的授权，从而减少用户的Gas消耗。1.1 传统approve的问题在传统的ERC-20代币中，用户需要通过approve方法来授权第三方合约或地址使用其代币。例如：function approve(address spender, uint256 amount) external returns (bool);这个过程需要用户发送一笔链上交易，并支付Gas费用。如果用户需要多次授权不同的合约或地址，每次都需要发送一笔交易，这不仅增加了用户的操作成本，还降低了用户体验。1.2 permit的优势permit功能通过链下签名的方式解决了这个问题。用户只需在链下签名一次，合约可以通过验证签名来获取用户的授权。这样，用户不需要发送链上交易，从而减少了Gas消耗。二、Permit的实现原理permit功能的实现依赖于EIP-712标准，该标准定义了一种结构化的签名方式，使得链下签名可以被链上合约验证。2.1 EIP-712结构化签名EIP-712定义了一种结构化的签名方式，允许用户在签名时包含更多的上下文信息。这样，用户在签名时可以清楚地知道自己在签署什么内容，从而减少签名的风险。permit功能使用EIP-712标准来生成和验证签名。具体来说，permit的签名数据结构如下：struct Permit { address owner; address spender; uint256 value; uint256 nonce; uint256 deadline; }owner: 代币的所有者地址。spender: 被授权的地址。value: 授权的代币数量。nonce: 所有者的当前nonce值，用于防止重放攻击。deadline: 签名的过期时间。2.2 Permit的签名过程生成签名数据：用户根据Permit结构生成签名数据，并使用EIP-712标准进行结构化签名。发送签名：用户将签名发送给第三方合约。验证签名：合约通过验证签名来获取用户的授权，并更新用户的allowance。2.3 Permit 的合约实现在智能合约中，permit 功能通常通过以下方式实现：function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external { require(block.timestamp <= deadline, "Permit: expired"); bytes32 structHash = keccak256( abi.encode( PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline ) ); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); require(signer == owner, "Permit: invalid signature"); _approve(owner, spender, value); }PERMIT_TYPEHASH: 是Permit结构的类型哈希，用于EIP-712签名。nonces[owner]: 是用户的当前 nonce 值，用于防止重放攻击。_hashTypedDataV4: 是EIP-712的哈希函数，用于生成结构化哈希。ECDSA.recover: 用于从签名中恢复签名者地址。三、使用Permit3.1 permit功能在以下场景中非常有用减少Gas消耗：在DeFi应用中，用户通常需要多次授权合约操作。使用permit功能，…

虚拟机 抽象
type: item
date: 2024-12-08T12:21:00+00:00
description: 通用高级的抽象的合约虚拟机设计规范账户抽象账户信息由字节码（Code）和存储（Storage）构成使用20长度字节数组类型的值来唯一标识（ID）账户以账户ID为键，以Code和Storage为值，构建Verkle树来保存所有账户的状态任何账户都可以接收输入（Input），在虚拟机里执行代码并保存新的执行结果（比如转账）如果账户的字节码为空，将使用具有默认接口功能的代码替代（这个代码可以采用硬编码的方式提供）因为所有账户都可以有字节码和存储，所以账户都可以视为合约预先部署一个代币合约，作为原生数字货币，用于矿工奖励发放和用户费用支付预先部署一个共识合约，接收区块输入，并验证、执行和存储它合约虚拟机在虚拟机中，所有账户统称为合约，合约执行代码需要消耗燃料（Gas），按照代码的复杂度来收取硬编码合约将区块链的一些核心功能转化为硬编码的合约实现，有以下优势相比字节码的方式合约调用能带来一致性的体验有效减少字节码的数量可以采用硬编码的方式实现，性能不会有太大影响从账户0x1开始分配特殊字节码购买Gas：共识合约会提供一个支付代币购买的接口，经过接口验证后内部调用此字节码为其增加Gas，仅共识合约可以调用重置合约：清空合约存储数据并使用新的字节码初始化（可以指定为空），类似以太坊合约部署，仅限重置账户自己创建合约：使用指定的字节码去初始化一个随机的合约，类似以太坊CREATE2字节码合约可以自定义代码来关闭重置功能，类似以太坊账户的合约销毁机制：不存在调用销毁字节码逻辑的合约是无法被销毁的交易执行用户指定一个目标合约和输入（符合一定规则的，一般会包含签名以及合约调用），发送到虚拟机中加载合约对应的代码开始执行，初始时虚拟机会暂借一定量的Gas（MinGas），这些Gas主要用调用购买Gas接口交易可以在耗尽MinGas之前调用共识合约提供的Gas购买接口添加更多Gas，否则交易会失败失败的交易会回滚状态，但不返还消耗来购买Gas的代币；不管成功或失败，多余的Gas会进行返还处理如果一笔交易没有购买过Gas，则不应该打包进区块中（取决于矿工逻辑）在交易结束（不管成功或失败）前都没有购买Gas的交易可以视为垃圾交易，理应直接丢弃垃圾交易为了避免无效交易的DOS攻击，需要在交易执行消耗少量Gas的时候就进行判断，如果还没有账户为这笔交易买单，则应该终止执行并将其视为垃圾交易。因为矿工激励规则，没有账户付Gas的交易矿工收益为零，所以矿工有权拒绝打包这类交易。灵活收费将Gas收费逻辑转移到虚拟机中实现，只要交易目标合约调用了共识合约的购买Gas接口即可，目标合约可以在购买Gas之前执行一些自定义代码（比如签名验证或其它一些检查），共识合约可以自定义购买Gas费的逻辑（比如某些账户免费或阶梯购买）交易安全合约有默认的接口，使用对应的私钥进行控制，用户可以更新代码实现自定义的规则，实现多签、托管、恢复等等功能，达到灵活控制账户的目的，后期还能采用升级默认的合约接口来提高安全性。重放攻击由账户自行防御，可采用类似nonce的机制或其它方法默认合约接口链合约存储区块（调用共识合约验证）查询区块参数配置查询共识合约验证一个新的区块执行其中的交易执行激励规则验证一笔交易系统合约重置账户创建账户删除账户

Ton链 Telegram小程序
type: item
date: 2024-11-24T13:23:00+00:00
description: 近年来，区块链技术的快速发展催生了众多创新应用，而Ton链作为其中的佼佼者，凭借其高效、低成本的特性，吸引了大量开发者和用户的关注。与此同时，Telegram作为全球最受欢迎的即时通讯应用之一，也在不断扩展其生态系统。当Ton链与Telegram相遇，便诞生了令人兴奋的Telegram小程序，为用户带来了全新的区块链体验。简介Ton（全称：The Open Network）是一个由多个组成部分构成的去中心化和开放的互联网平台。这些组成部分包括：TON区块链、TON DNS、TON存储和TON网站。TON区块链是TON底层基础设施的核心，由Telegram团队最初设计和社区进行开发。旨在为用户提供快速、安全且低成本的去中心化服务。Ton链的设计理念是让区块链技术更加普及，尤其是在支付、存储和通信等领域。其核心技术包括：高吞吐量：Ton链能够处理数百万笔交易，远超传统区块链。低交易费用：用户可以在几乎零成本的情况下完成交易。智能合约支持：开发者可以在Ton链上构建去中心化应用（DApps）。Telegram不仅仅是一个聊天工具，它还是一个开放的平台，允许开发者通过其API和Bot功能创建各种小程序。这些小程序可以集成到聊天中，为用户提供丰富的功能，例如支付、游戏、新闻推送等。随着Ton链的推出，Telegram小程序的功能得到了进一步扩展，尤其是在区块链领域。Telegram小程序（TMA）是在Telegram中运行的Web应用，使用Web技术构建——HTML、CSS和JavaScript。在Telegram上构建基于Ton链的去中心化的小程序应用，即可拥有潜在的大量Telegram用户基础。核心步骤在Telegram上面创建机器人，并在机器人下面创建小程序，创建过程中按照提示操作即可使用Web技术和Telegram提供的SDK编写小程序前端，构建且部署，得到一个链接，过程和开发部署一般Web网站一样将创建的小程序和部署的前端链接绑定起来，就是修改小程序的Web App URL为上一步部署好的地址然后在Telegram客户端里面打开小程序，可在小程序中连接Ton链，开发去中心化类别的应用打开BotFather，并使用/newbot命令，再使用/newapp命令，官方教程Ton钱包Ton Connect协议有许多的Ton链的钱包提供支持，只要钱包支持这个协议，使用此协议的小程序就可以连接到这个Ton链钱包。连接钱包后，能获取到钱包的信息以及账户信息，还可以签名并发送交易到Ton链上，实现与区块链交互，构建去中心化类别的小程序应用。小程序集成步骤（其它Web前端也是如此）如下：安装SDK：yarn add @tonconnect/ui初始化：准备一个manifest.json文件，配置到项目的根目录，例如https://myapp.com/tonconnect-manifest.json在应用程序中导入SDK，创建@tonconnect/ui的连接器实体对象接下来就可以使用此对象提供的接口发送交易，进行Ton转账等区块链操作官方教程STON.fiSTON.fi是一个基于TON区块链建立的去中心化自动做市商 (AMM)，提供几乎零费用、低滑点、极其简单的界面以及支持众多的TON钱包连接。并且提供了SDK，前端可轻松集成后进行代币的兑换。它提供了三种兑换方式（jetton是Ton链的代币，类似于以太坊的ERC20）：TON => jettonjetton => jettonjetton => Ton下面是使用Ton币购买jetton代币的示例，更多细节参考官方文档import { TonClient, toNano } from "@ton/ton"; import { DEX, pTON } from "@ston-fi/sdk"; const client = new TonClient({ endpoint: "https://toncenter.com/api/v2/jsonRPC", }); const router = client.open(new DEX.v1.Router()); // swap 1 TON to STON but not less than 1 nano STON const txParams = await router.getSwapTonToJettonTxParams({ userWalletAddress: "", // ! replace with your address proxyTon: new pTON.v1(), offerAmount: toNano("1"), askJettonAddress: "EQA2kCVNwVsil2EM2mB0SkXytxCqQjS4mttjDpnX…

hardhat 可升级合约
type: item
date: 2024-11-09T15:20:00+00:00
description: 基于hardhat框架进行合约开发，使用OpenZeppelin库实现可升级的智能合约搭建开发环境操作系统：Linuxnode：23.1.0yarn：1.22.22hardhat：2.22.171、创建空白项目mkdir demo && cd demo yarn init -y可更改yarn的源（默认的太慢还可能导致安装包失败）：yarn config set registry https://registry.npmmirror.com2、集成hardhat添加包到项目中yarn add -D hardhat初始化环境yarn hardhat选择创建JavaScript项目，并按照提示创建相关文件和安装依赖包888 888 888 888 888 888 888 888 888 888 888 888 888 888 888 8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 888 888 "88b 888P" d88" 888 888 "88b "88b 888 888 888 .d888888 888 888 888 888 888 .d888888 888 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. 888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 Welcome to Hardhat v2.22.17 ✔ What do you want to do? · Create a JavaScript project ✔ Hardhat project root: · /home/swwx/demo ✔ Do you want to add a .gitignore? (Y/n) · y ✔ Do you want to install this sample project's dependencies with yarn (@nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-verify chai hardhat-gas-reporter solidity-coverage @nomicfoundation/hardhat-ignition @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-chai-matchers @nomicfoundation/hardhat-ethers ethers @typechain/hardhat typechain @typechain/ethers-v6 @nomicfoundation/hardhat-ignition-ethers)? (Y/n) · y初始化时自动配置了一个示例合约，可以运行以下命令查看效果yarn hardhat compile：编译智能合约yarn hardhat test：执行合约测试yarn hardhat node：启动一个虚拟的本地测试节点yarn hardhat help：查看帮助信息3、安装openzeppelin升级插件和合约库yarn add -D @openzeppelin/hardhat-upgrades yarn add @openzeppelin/contracts @openzeppelin/contracts-upgradeable修改hardhat配置文件hardhat.config.js，导入插件require("@nomicfoundation/hardhat-toolbox"); require("@openzeppelin/hardhat-upgrades"); /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: "0.8.28", };开发升级合约部署到EVM的合约代码是不能修改的，一般可以使用代理合约的方式实现合约升级，代理合约保存数据，逻辑合约保存可执行代码，并使用delegatecall字节码连接在一起。一般来说，升级代码实现有两种方式，一是在将升级管理代码放在代理合约中，但这样会增加代理合约的大小，增加部署代理的成本，二是将升级代码放到实现合约中，由代理合约使用delegatecall字节码进行调用，这样会增加逻辑合约的大小，但是可以在将来升级的时候禁用升级接口，实现不再更新合约的功能。通常，代理模式使用单个实现合约和单个代理合约。然而，多个代理也可以使用相同的实现，这种代理叫做…