Cointime

扫码下载App
iOS & Android

超越边界:深入探索Scroll zkEVM的智能合约开发

个人专家

作者:Priyank Gupta. 编译:Cointime:QDD.

我撰写了这篇文章,作为对Scroll zkEVM的技术介绍,供希望尝试该网络的智能合约开发者阅读。

在这篇文章中,我们将:

1. 了解Scroll zkEVM以及如何开始使用它的Alpha测试网络。

2. 使用Foundry搭建开发环境,并编写一个智能合约,在Alpha测试网络上基于伪随机数生成函数分发ETH。

3. 调整智能合约以符合Alpha测试网络所需的精确规格。

4. 借助Solidity脚本部署我们的智能合约。

5. 通过Foundry的命令行在Alpha测试网络上验证我们的智能合约。

通过本文,你将学会如何使用Foundry将你的智能合约部署到Scroll的Alpha测试网络中。

什么是Scroll zkEVM?

Scroll

Scroll zkEVM是一个即将推出的第二层区块链解决方案,专为增加以太坊的可扩展性而设计。

Scroll和类似的平台(如Polygon zkEVM)的区别在于使用零知识证明(ZK证明)。ZK证明通过将大量交易捆绑在一起,并一次性写入以太坊,显著降低与在以太坊上逐个处理每个交易相比的交易费用。

像Scroll这样的zkEVM的最好之处在于:智能合约开发者无需理解底层的ZK技术,即可在更便宜和可扩展的解决方案上部署与EVM兼容的智能合约。

先决条件

1. 确保你的钱包中有一些Goerli ETH。是的,我知道Goerli已经弃用了,但你现在还需要它。

2. 对区块链有基本的理解,并具备一些Solidity的经验。

3. 如果你之前没有使用过Foundry,请建议你查看我之前为一个研讨会制作的这个Github仓库的README。

4. 不需要看整个视频,如果你以前没有使用过Foundry,请快速浏览一下README文件。

首先要做的事情:桥接!

在不涉及太多ZK特定的内容的情况下,请知道Scroll网络上的ETH是与以太坊主网上的ETH相对应的。镜像意味着Scroll团队已在Scroll网络(目前是Alpha测试网络)和对应的ETH网络(目前是Goerli测试网络)上部署了桥接智能合约。

因此,要在Alpha测试网络上获得一些ETH以支付燃气费,你需要将一些Goerli ETH存入Goerli上的桥接合约中。

镜像也可以反向操作。

开始操作:

1. 访问Scroll的UI界面,该界面允许你与桥接合约进行交互。

2. 将你的Metamask钱包连接到网页。

3. 确保你将ETH发送到Scroll网络,而不是相反。按照界面上的提示(它很直观),确认桥接。

确认后,你可能需要等待30-45分钟,然后才能在Alpha测试网络上收到ETH。所以你需要耐心等待一段时间。

一旦在Alpha测试网络上有了一些ETH,你就可以开始了!

初始化一个Foundry项目

Foundry是最新的智能合约开发框架之一,越来越受欢迎。

要安装Foundry,请参考以下命令或查看Foundry-book

运行以下命令下载foundryup

curl -L https://foundry.paradigm.xyz | bash

然后重新启动终端,然后通过运行以下命令安装Foundry:

foundryup

安装完成后,在新的目录中打开一个新的终端。你可以使用以下命令初始化一个新的Foundry项目:

forge init

一些建议:

1. 所有的智能合约默认都创建在src目录下。

2. forge install命令可以在lib目录下安装新的git子模块。

3. 默认情况下,所有的测试合约都在test目录下定义,并且通常以.t.sol为后缀,这意味着一个名为hello.sol的合约文件将有一个名为hello.t.sol的文件,按照惯例。你可以使用forge test命令执行所有的测试文件。

4. 你可以通过配置foundry.toml文件来控制Foundry的行为。这个Github页面提供了对toml文件的完整参考。我还编写了一个包含默认值列表的gist。

5. script目录包含了Foundry项目的部署和可执行脚本。

每当你对代码进行任何更改时,你可以使用以下命令编译所有智能合约:

forge build

操作码和字节码:快速入门

在编写智能合约之前,让我们了解一些概念,这些概念有助于理解整个情况。

对于那些不知道的人,EVM不执行Solidity或任何其他智能合约开发语言。EVM甚至不知道这些语言的存在,也不关心。这对Scroll zkEVM也是适用的。

发生的情况是,任何智能合约代码都被分解成一组可由EVM执行的指令集,称为字节码,这是EVM实际执行的内容。

好了,但是操作码是什么,为什么我们要关心呢?还记得我说过字节码是一个“指令集”吗?

嗯,每个操作码都是一条指令,与其他操作码结合在一起,构成任何智能合约的字节码。作为区块链开发者,你必须处理操作码,这是最低级别的计算。

例如,如果你在Solidity中使用了block.number,你实际上调用了NUMBER操作码。关于EVM支持的所有操作码的完整参考(不要与Scroll的zkEVM混淆)可以在以太坊基金会的网站上找到。

让我用一个例子清楚地解释整个概念的意义。

看一下这个简单的智能合约:

只是一个返回两个数字之和的函数。等效的操作码指令会是什么样子?请查看我创建的这个Gist。你还可以在Etherscan上查看此合约,以验证字节码和操作码。

这一节可能看起来像一个不相关的插曲,但相信我,在接下来的章节中,这将更加清晰明了。

编写智能合约

最后,让我们完成它。

进入src目录并创建一个名为ScrollTutorial.sol的新文件。

将以下代码粘贴到其中:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

contract Dispenser {

   
//mapping to keep track of addresses that have already withdrawn

   
mapping(address => bool) public hasWithdrawn;

   
function withdraw() public {

       
require(

         
  !hasWithdrawn[msg.sender],

           
"You have already withdrawn once, sorry!. Try again from a
different address!"

       
);

       
require(

           
address(this).balance > 0.5 ether,

           
"Not enough funds in the contract right now"

        );

       
uint256 randomNumber = uint256(

           
keccak256(

                abi.encodePacked(

                    blockhash(block.number -
100),

                    block.prevrandao,

                    block.coinbase

                )

       
    )

       
) % 2;

       
// Check that the random number is even

       
require(

           
randomNumber == 0,

           
"Sorry but the hash generated was an odd number, try again from a
different address!"

       
);

       
// Set the hasWithdrawn flag for this address to true

       
hasWithdrawn[msg.sender] = true;

       
// Transfer 0.5 ether to the address

       
payable(msg.sender).transfer(0.5 ether);

    }

   
function deposit() public payable {}

}

这是一个简单直观的智能合约。让我们快速理解一下代码:

1. 我们希望每个地址只能提取0.5 ETH一次;mapping hasWithdrawn 用于跟踪已成功提取ETH的所有地址。

2. deposit函数是一个简单的可支付函数,允许我们的合约接收ETH。

3. withdraw函数是整个魔术发生的地方。

让我们更详细地看一下withdraw函数。

1. 函数开头的前两个require语句确保每个地址只能提取一次,并且合约中有足够的ETH进行交易。

2. randomNumber变量是我们使用几个实时值生成的伪随机数。我们很快会详细了解它们。

3. abi.encodePacked函数接收所有的参数,并将它们连接成一个单独的字节字符串。

4. keccak256函数将生成接收到的输入的Keccak-256哈希值。我们对该函数输出进行取模运算,以检查生成的哈希值是否为偶数。

5. 接下来,如果哈希值为偶数,我们支付ETH并更新映射关系。

要编译智能合约,请在终端中运行以下命令:

forge build

专业提示#1:PREVRENDAO是一个相对较新的操作码,取代了DIFFICULTY操作码,只支持Solidity版本0.8.18及以上。请确保相应地配置Solidity版本。

我们的代码存在的问题

这段代码远远不够适用于生产环境,但让我们首先讨论一个更基本的问题。

回想一下,我提供了一个EVM支持的操作码列表。

不幸的是,截至目前,Scroll的zkEVM并不支持所有这些操作码。

它支持其中大部分,但如果你要为zkEVM(任何zkEVM)开发智能合约,你必须了解网络和EVM之间在操作码支持方面的差异。

请重新检查代码并查看我们用于生成随机数的值。让我们来看看在我们的智能合约中将无法正常工作的部分:

操作码 Solidity等效 行为差异
BLOCKHASH blockHash(BlockNum) 我们使用最新区块前100个区块的哈希作为随机数哈希的一部分。然而,Scroll zkEVM不支持获取如此旧的区块的哈希。如果区块号超出了支持的范围,将返回0。以太坊支持:[最新-1] - [最新-256] Scroll zkEVM支持:[最新-1] 
PREVRANDAO block.prevrendao 将PREVRENDAO视为一个伪随机源数字,你可以在此处阅读更多信息。以太坊行为:返回一个伪随机数 Scroll zkEVM行为:返回0,没有随机性 
COINBASE block.coinbase EVM行为:返回区块的验证者地址。由于ETH验证者是随机选择的,该数字是伪随机的。Scroll行为:目前仅返回一个地址,没有随机性

因此,我们用来生成randomNumber的这三个值在EVM上具有伪随机行为。然而,它们要么无法工作,要么返回一个常量值,使它们对我们的目的毫无用处。

但说实话,即使Scroll支持所有这些操作码,这仍然不是一个适用于生产的合约。没有一个严肃的智能合约依赖将区块的值进行哈希处理来生成随机数。要部署利用随机性的智能合约,请查看Chainlink的VRF服务

调整智能合约

由于Chainlink不支持Scroll,我们将退而求其次使用伪随机性。

这次,我们将以两种方式稍微更改withdraw函数:

1. 我们现在允许用户在调用withdraw函数时传递一个参数。我们将使用该参数作为randomNumber的哈希的一部分,以便用户对生成的哈希有一定的控制。

2. 我们将其他两个值替换为前一个区块的区块哈希和当前区块的时间戳。这并不是一个很好的随机性来源,但目前这是我所知道的最好的解决方案。

如果你有更好的解决方案,请随时告诉我。

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

contract Dispenser {

   
//mapping to keep track of addresses that have already withdrawn

   
mapping(address => bool) public hasWithdrawn;

   
function withdraw(uint seedValue) public {

       
require(

           
!hasWithdrawn[msg.sender],

           
"You have already withdrawn once, sorry!. Try again from a
different address!"

     
  );

       
require(

           
address(this).balance > 0.5 ether,

           
"Not enough funds in the contract right now"

       
);

       
uint256 randomNumber = uint256(

           
keccak256(

                abi.encodePacked(

                    blockhash(block.number -
1),

                    block.timestamp,

                    seedValue

                )

           
)

       
) % 2;

       
// Check that the random number is even

       
require(

           
randomNumber == 0,

           
"Sorry but the hash generated was an odd number."

       
);

       
// Set the hasWithdrawn flag for this address to true

       
hasWithdrawn[msg.sender] = true;

       
// Transfer 0.5 ether to the address

       
payable(msg.sender).transfer(0.5 ether);

    }

   
function deposit() public payable {}

}

部署和验证我们的智能合约

我们需要向Foundry传递一些值来部署我们的智能合约。我们可以直接在命令行中部署合约时进行配置,但在.env文件中进行配置更加方便。在你的项目目录中创建一个新的.env文件。

我们需要在env文件中传递两个值:

1. RPC_URL:Foundry将需要一个RPC URL来连接Alpha测试网络。我们可以从Scroll的文档中获取Alpha测试网络的公共RPC URL。

2. PRIVATE_KEY:我们将需要一个在Alpha测试网络上具有一些ETH的钱包的私钥来签署交易。你的env文件应该如下所示:

RPC_URL=https://alpha-rpc.scroll.io/l2

PRIVATE_KEY=1dh12j1XXXXXXXXXXXXXh1pqdfjnma91k

保存你的env文件。运行以下命令将这些变量加载到你的终端中:

source .env

现在,我们已经安全地设置了所有敏感信息,让我们编写一个脚本来部署我们的合约。你也可以使用forge create命令直接从命令行部署,但我觉得脚本更加优雅。

在script目录中创建一个名为ScrollTutorial.s.sol的文件。在文件中,粘贴以下代码:

// SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.8.13;

import "forge-std/Script.sol";

import {Dispenser} from "../src/ScrollTutorial.sol";

contract MyScript is Script {

   
function run() external {

       
uint256 PrivateKey = vm.envUint("PRIVATE_KEY");

       
vm.startBroadcast(PrivateKey);

       
Dispenser dispenser = new Dispenser();

       
vm.stopBroadcast();

    }

}

让我们解释一下这里发生了什么:

1. 在前两行中,我们从forge标准库导入了脚本工具和我们的智能合约。

2. forge-std库提供了vm.sol接口,以使用有价值的秘籍。envUint函数可用于访问我们在env文件中的私钥。

3. 在startBroadcast和stopBroadcast之间的任何事务都可以发送到链上。在我们的情况下,我们需要创建一个新的智能合约实例。

保存脚本文件。现在我们准备好部署了。在终端中运行以下命令:

forge script script/ScrollTutorial.s.sol:MyScript --rpc-url $RPC_URL --broadcast --legacy -vvvv

专业提示#2:Foundry允许我们使用“-v”标志来配置命令行的详细程度。我倾向于大多数时候使用最高详细程度。你可以在此处阅读更多信息。

专业提示#3:对于Scroll和zkSync等zkEVM,你可能需要通过Foundry传递“--legacy”标志来部署合约,因为它们通常不支持EIP-1559。

Scroll的文档提供了一个Blockscout资源管理器的API URL,可以用来验证我们的合约。在终端中运行以下命令来验证你的合约:

forge verify-contract <CONTRACT_ADDRESS> src/ScrollTutorial.sol:Dispenser --chain-id 534353 --verifier-url https://blockscout.scroll.io/api/ --verifier blockscout

注意:Blockscout API似乎已经关闭,并且其行为被Scroll文档确认为不一致。我无法从命令行验证我的合约,你也可能遇到同样的问题。不过,你可以通过Blockscout的UI进行验证。

合约验证完成后,你可以在Blockscout的UI中与其进行交互。

结论

在本文中,我们介绍了Scroll zkEVM以及作为智能合约开发人员如何通过最小配置将智能合约部署到该网络。Scroll Mainnet即将推出,现在是开始使用这项出色新技术的最佳时机。

评论

所有评论

推荐阅读

  • 5月8日晚间要闻速递

    1. BTC跌破62000美元

  • 加密初创公司Lagrange Labs融资 1320 万美元

    Peter Thiel 的 Founders Fund 领投了加密初创公司 Lagrange Labs 一轮 1320 万美元的种子轮融资。除了 Founders Fund 之外,Lagrange 的种子轮融资还包括 Archetype Ventures、1kx、Maven11、Fenbushi Capital、Volt Capital、CMT Digital、Mantle 和 Ecosystem 的参与

  • 加密一级市场交易商Arbelos完成2800万美元融资,Dragonfly领投

    Arbelos 完成 2800 万美元融资,本轮融资由 Dragonfly 领投、FalcolnX、Circle、Paxos、Polygon 和 Deribit 参投。Arbelos Markets 将主要专注于机构参与者的衍生品和场外交易,为对冲基金和风险投资公司等公司提供交易流动性,作为期权和期货等热门产品的交易对手。

  • 跨链互操作协议Owlto Finance完成800万美元战略轮融资,Bixin Ventures等领投

    跨链互操作协议 Owlto Finance 宣布完成 800 万美元战略轮融资,本轮融资由 Bixin Ventures 和 CE Innovation Capital 联合领投,Presto、Hailstone Labs、Skyland Ventures、Blocore、SNZ Capital、BESTO、Kroma、Coinseeker.co、Stratified Capital、X21 Digital、Maxx Capital、Incubate Fund、GSR、ChainCatcher 等跟投。 本轮融资主要用于加速 AI 意图跨链产品升级、模块化跨链互操协议开发、全球化运营和市场营销、全链流动性方案 V2、资本化市场运作等。

  • 英国新银行Monzo获得1.9亿美元融资,Hedosophia和CapitalG领投

    英国新银行Monzo获得1.9亿美元融资,Hedosophia和CapitalG(Alphabet的独立成长基金)领投,最新的融资使Monzo今年的融资总额达到6.1亿美元,融资后的估值为52亿美元,Monzo首席执行官兼联合创始人TS Anil表示,计划利用这笔现金打造新产品,并加快国际扩张计划。

  • 香港证监会:公众需提防 Quantum AI 涉嫌从事虚拟资产相关欺诈行为

    香港证监会告诫公众提防 Quantum AI 涉嫌从事虚拟资产相关欺诈行为,据悉 Quantum AI 声称利用其相关人工智能技术来提供加密货币交易服务。 证监会怀疑,Quantum AI 在其网站和社交媒体上使用以人工智能制成、冒充埃隆·马斯克先生(Mr Elon Musk)的深度伪造影片及照片,借此欺骗公众,让他们以为马斯克先生 是Quantum AI 的相关技术的开发者。 香港警务处已应证监会的要求,采取行动封锁 Quantum AI 的网站并移除相关社交媒体专页。 虽然警方已采取行动,但公众应提防骗徒可能持续建立域名相似的网站及社交媒体专页。

  • SEC认为Ripple并未违反任何规则但未来仍可能对其采取类似行动

    Ripple Labs和美国证券交易委员会(SEC)在法律斗争中取得了重大进展,SEC在诉讼的补救阶段提交了最终答复。在最近对补救措施简报的回应中,SEC对Ripple的主张提出了质疑,即该区块链初创公司的行为并不鲁莽,而且XRP的法律地位不应该存在“广泛的不确定性”,尽管法院此前拒绝了这种“公平通知”辩护。 尽管自2020年发起XRP诉讼以来,Ripple并未违反任何规则,但SEC仍对Ripple未来是否可能采取类似行动保持立场。SEC认为,Ripple保证在诉讼后改变其行为并不能成为避免禁令的理由。根据SEC的说法,Ripple声称遵循法律指导并根据诉讼命令重组未来XRP销售的说法具有误导性。SEC认为Ripple误解了该命令,并且未能接受其对合规性的影响。

  • Messari发布Fantom Q1报告:市值环比增长101%,DeFi TVL环比增长59%

    Messari近日发布Fantom 2024年Q1状态报告,要点如下: ·Fantom在多个关键指标上都实现了环比增长,包括市值(+101%)、日均活跃地址(+24%)、美元计价的DeFiTVL(+59%)、稳定币市值(+39%)和日均DEX交易量(+64%); ·FTM总质押量环比增长17%,达到13亿枚,合格供应质押量占比也环比增长16%,至44.6%; ·今年3月,Fantom的DEX月度交易量在过去一年中首次超过10亿美元,3月DEX日均交易量为3790万美元,比2月(570万美元)高出近7倍,比1月(660万美元)高出6倍; ·3月25日,Fantom基金会首席执行官Michael Kong公布了Sonic初步发布计划(计划24年Q3发布),计划包括规范桥接、简化的质押系统、构建者grants、奖励计划、规范稳定币等; ·Sonic Labs孵化器项目的五名获胜者在Q1中被选出。每个项目将获得20万枚FTM,并在Sonic主网上线之前获得开发支持。

  • OpenSea上以太坊NFT日交易量跌至两年低点,较峰值跌超99%

    5月8日消息,前Proof研究员punk9059在X平台表示,目前,OpenSea每天在以太坊NFT市场上的交易量约为600枚ETH,这是自2021年5月NFT牛市开始之前的最低水平。这一数字比2022年5月的峰值下降了99.1%,当时OpenSea每天交易量达到了66,000枚ETH。

  • ETH跌破3000美元

    行情显示,ETH跌破3000美元,现报2999.41美元,日内跌幅达到2.08%,行情波动较大,请做好风险控制。