2025年yarn build命令(yarn logs 命令)

yarn build命令(yarn logs 命令)textarea id md view content style Untitled png https img learnblockch cn attachments 2022 09 a2b2gA9X6321 png scale 40 本文列举了 foundry 中常用的命令 方便以后查询使用 textarea

大家好,我是讯享网,很高兴认识大家。



 <textarea id="md_view_content" style="">![Untitled.png](https://img.learnblockchain.cn/attachments/2022/09/a2b2gA9X63218bb03c553.png!/scale/40) 

讯享网

本文列举了foundry中常用的命令,方便以后查询使用。

一. 为什么要用foundry

  • 全面支持solidity,可有效减少上下文切换

    与hardhat+ethers组合工具相比,hardhat+ethers合约使用solidity,而部署测试等使用 js或者ts。而对于foundry工具,合约、部署、测试等都使用solidity,不需要在多种编程语言之间进行切换。

  • 功能更齐全。如cast命令可以直接从etherscan下载源代码,可以直接从abi 生成interface等功能。
  • 运行速度更快。

二. 软件安装方法

官方网站:getfoundry.sh

在mac环境下,使用下面命令进行安装

讯享网curl -L https://foundry.paradigm.xyz | bash source ~/.zshrc # 每次执行foundryup时,都会下载最新的cast,anvil,forge程序 foundryup 

foundry系列的工具,主要包含三大组件,分别对应不同的功能,下面会每个组件依次试用。

  • forge:主要用来开发、编译、部署合约。
  • cast:执行以太坊 RPC 调用的命令行工具
  • anvil:本地模拟节点环境,类似于ganache-cli的功能。

三. cast使用

&lt;aside&gt; 😀 我的 ETH alchemy的RPC接点 https://eth-mainnet.g.alchemy.com/v2/*

export ETH_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/

&lt;/aside&gt;

cast 是 Foundry 用于执行以太坊 RPC 调用的命令行工具。您可以进行智能合约调用发送交易或检索任何类型的链数据

cast与web3交互的小工具,即使不是代码开发的人员也会经常使用该工具与链上数据进行查询等交互。

cast rpc eth_blockNumber –rpc-url=$ETH_RPC_URL

&lt;aside&gt; 😀 cast支持环境变量ETH_RPC_URL,将RPC节点设置到环境变量ETH_RPC_URL中。 对带有–rpc-url的参数的cast命令中,可直接从环境变量中直接读取,不需要在命令中体现。

&lt;/aside&gt;

3.1 查询功能

查询区块高度-cast rpc eth_blockNumber

cast rpc eth_blockNumber --rpc-url=$ETH_RPC_URL &quot;0xebc18f&quot; (base) ➜ ~ cast --to-dec &quot;0xebc18f&quot;  (base) ➜ ~ cast --to-dec 0xebc18f  

Untitled 1.png
讯享网

查询区块信息-cast block &lt;blockNumer&gt;

讯享网 (base) ➜ ~ cast block  --rpc-url=$ETH_RPC_URL baseFeePerGas  difficulty  extraData 0x706f6f6c696e2e636f6d21bb45000ef0fc7e9d gasLimit  gasUsed  transactions: [ 0x1ac18cdb12a6cbfef4e2bc64faaf58507e057fc27f62d1e23a7 0x1b0032cb42ade1add87a25f367b4142ebeabc936f2a6f403bcd50e6dc5 0x28afc8b0659d88ffb03b803b01ebb6e3b70a0c1cf941d7f6fafc 

查询交易信息-cast tx &lt;交易hash&gt;

(base) ➜ ~ cast tx 0xd38950f391b91fef3daaf516d86470abdba5ace230b942d --rpc-url=$ETH_RPC_URL blockHash 0xd73fb0230f3ab6e8a8c9ba5698c1ec7beb5aa23175eb5d507b748a7ea blockNumber  from 0x796ed889d874dEeE8fE495F6ccf7db193B gas 96677 gasPrice  hash 0xd38950f391b91fef3daaf516d86470abdba5ace230b942d input 0xa0712d0000000000000000000000000000000000000000000000000000002 nonce 0 r 0x31c9c3e6d7cda4b7cf2c17355acc20fdff6b83d2c134d66ea2f s 0x1775d3ae05cbabc23219e18b27e9ac29dd0dbdafc165bbab052f7ba23 to 0xc93f78f08c7E9526C78Da56Cba1DEE8287baCb27 transactionIndex 4 v 1 value 0 

交易回执查询-cast receipt &lt;receipt_hash&gt;

讯享网base) ➜ ~ cast receipt 0xd38950f391b91fef3daaf516d86470abdba5ace230b942d --rpc-url=$ETH_RPC_URL blockHash 0xd73fb0230f3ab6e8a8c9ba5698c1ec7beb5aa23175eb5d507b748a7ea blockNumber  contractAddress cumulativeGasUsed  effectiveGasPrice  gasUsed 86319 logs [{&quot;address&quot;:&quot;0xc93f78f08c7e9526c78da56cba1dee8287bacb27&quot;,&quot;topics&quot;:[&quot;0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef&quot;,&quot;0x000000000000000000000000000000000000000000000000 使用 --json 以json格式返回数据,使用管道输入给jq进行处 cast receipt 0xd38950f391b91fef3daaf516d86470abdba5ace230b942d --rpc-url=$ETH_RPC_URL --json | jq 

&gt; 🤣 jq工具的使用 &gt; &gt; jq 一个灵活的轻量级命令行JSON处理器,jq 用于处理JSON输入,将给定过滤器应用于其JSON文本输入并在标准输出上将过滤器的结果生成为JSON。 &gt; &gt; 1. 下载https://github.com/stedolan/jq/releases &gt; 2. 移动到 /usr/local/bin,并命名成jq,设置成可执行属性。

查询calldata数据-cast pretty-calldata &lt;十六进制数据&gt;

pretty-calldata 命令会取出 &lt;十六进制数据&gt;中的前4个字节,从在线网站的数据库(https://sig.eth.samczsun.com/)中比对4字节的selector对应的函数原型,并将 &lt;十六进制数据&gt;中的后面部分的数据按照函数原型进行格式化输出。

 查看input数据 (base) ➜ ~ cast tx 0x3574c7c9b34df46d7476c5a8e9fb48b2bf007df7d5d021ef9aa79983f4b13f92 --rpc-url=$ETH_RPC_URL input 0xa9059cbb0000000000000000000000007f1949e62203a83ad6e6be0a819f93ef9d000000000000000000000000000000000000000000038e8f7792d (base) ➜ ~ cast pretty-calldata 0xa9059cbb0000000000000000000000007f1949e62203a83ad6e6be0a819f93ef9d000000000000000000000000000000000000000000038e8f7792d Possible methods: - transfer(address,uint256) ------------ [0]: 0000000000000000000000007f1949e62203a83ad6e6be0a819f93ef9d [1]: 000000000000000000000000000000000000000000038e8f7792d 

可以通过cast 4byte &lt;十六进制数据&gt; 在查询函数selector对应的函数原型。

讯享网 # 查询0xa9059cbb selector对应的函数原型 (base) ➜ ~ cast 4byte 0xa9059cbb transfer(address,uint256) # 使用keccak计算函数原型对应的hash,可以发现hash的前4个字节就是selector (base) ➜ ~ cast keccak &quot;transfer(address,uint256)&quot; 0xa9059cbb2ab09ebf4a59a5d0623ade346d962bcd4e46b11da047c9049b (base) ➜ ~ cast sig &quot;transfer(address,uint256)&quot; 0xa9059cbb 

查询topic日志对应的函数原型-cast 4byte-event &lt;topic&gt;

Untitled 2.png

 (base) ➜ ~ cast 4byte-event 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3cc2402c5c5cc9109c Deposit(address,uint256) 

3.2 交易模拟-cast run

cast run命令

以*defi直接价格操纵经典案例-tcrToken被黑事件中的*交易为例,可参考https://learnblockchain.cn/article/4491

对应的交易为0x81e9918e248d14d78ff7bfd9f456c6ded14fdfb69db

讯享网(base) ➜ ~ cast run 0x81e9918e248d14d78ff7bfd9f456c6ded14fdfb69db 

3.3 钱包相关功能-cast wallet

使用帮助

(base) ➜ ~ cast wallet -h cast-wallet Wallet management utilities. USAGE: cast wallet &lt;SUBCOMMAND&gt; OPTIONS: -h, --help Print help information SUBCOMMANDS: address Convert a private key to an address. [aliases: a, addr] help Print this message or the help of the given subcommand(s) new Create a new random keypair. [aliases: n] sign Sign a message. [aliases: s] vanity Generate a vanity address. [aliases: va] verify Verify the signature of a message. [aliases: v] 

创建钱包

通过cast wallet new 创建新的钱包

讯享网(base) ➜ ~ cast wallet new Successfully created new keypair. Address: 0x382B0DbBc1b78B355eBB747E2F378bC711 

直接跟目录名,将钱包保存到keystore目录中

(base) ➜ cast_basic cast wallet new keystore Insert secret: Created new encrypted keystore file: `/Users/mamaogang/Nextcloud/code/eth_test/foundry/cast_basic/keystore/8c0cb584-95aa-4f63-924d-d8c5ab92f1bf` Public Address of the key: 0xb18A7BC0c376CB3be07CCCb61d8e33ce8B 

Untitled 4.png

签名-cast wallet sign

Untitled 5.png ENS功能-cast resolve-name和cast lookup-address

讯享网(base) ➜ cast_basic cast resolve-name vatalik.eth 0x7d66bD3dA15e0dc46afeD (base) ➜ cast_basic cast lookup-address 0x7d66bD3dA15e0dc46afeD Error: ens name not found: 7d66bd3da15e0dc46afed.addr.reverse 

Untitled 6.png

3.4 合约相关功能

在使用查看源代码功能之前,需要设置ETHERSCAN_API_KEY的环境变量

export ETHERSCAN_API_KEY=NZMQ7KC5CD5BND19KMBQFA3BI3QJUTG53V 

WETH 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2et

讯享网export WETH=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 

查看源代码-cast etherscan-source

cast etherscan-source \(WETH 查看\)WETH的源代码。

使用-d参数,将结果保存到指定目录下。

(base) ➜ cast_basic cast etherscan-source $WETH -d weth_source (base) ➜ cast_basic vi weth_source/WETH9/WETH9.sol 

Untitled 7.png

调用合约函数-cast call

讯享网cast call $WETH &quot;balanceOf(address)&quot; 0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e (base) ➜ cast_basic cast --to-dec 0x00000000000000000000000000000000000000000000bdb51a04b5aa8eb6431e 82 

Untitled 8.png

查询合约的slot的存储位置-cast index

cast index 根据KEY_TYPE的类型和KEY,及SLOT_NUMBER计算出存储位置

帮助说明

Untitled 9.png

问题:计算0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e账户在$WETH token中的余额,可以使用两种方式取得。

  • 常规函数调用方式
  • 读取合约slot存储方式
  1. 常规函数调用方式

    采用合约函数调用的方式,可以看到该账户下有bdb51a04b5aa8eb6431e 个WETH.

    (base) ➜ cast_basic cast call $WETH &quot;balanceOf(address)&quot; 0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e 0x00000000000000000000000000000000000000000000bdb51a04b5aa8eb6431e 
  2. 读取合约slot存储方式

    先根据WETH的源代码,分析得到balanceOf状态变量位于第3个slot,如何获得源代码?可以通过cast etherscan-source $WETH -d 目录 命令来获得。源代码如下:

    讯享网pragma solidity ^0.4.18; contract WETH9 { string public name = &quot;Wrapped Ether&quot;; string public symbol = &quot;WETH&quot;; uint8 public decimals = 18; event Approval(address indexed src, address indexed guy, uint wad); event Transfer(address indexed src, address indexed dst, uint wad); event Deposit(address indexed dst, uint wad); event Withdrawal(address indexed src, uint wad); mapping (address =&gt; uint) public balanceOf; mapping (address =&gt; mapping (address =&gt; uint)) public allowance; function() public payable { deposit(); } 

    通过slot来读取

    # 先计算出KEY_TYPE为address,KEY为0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e,slot为3,所对应的存储位置。 (base) ➜ cast_basic cast index address 0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e 3 0x1f8193c3f94e8840dc3a6dfc0bc012432d338ef33c4f3e4b3aca0d6d3c5a09b6 # 取出对应存储位置的原始数据,因为为address=&gt;int,所以取出来就没int (base) ➜ cast_basic cast storage $WETH 0x1f8193c3f94e8840dc3a6dfc0bc012432d338ef33c4f3e4b3aca0d6d3c5a09b6 0x00000000000000000000000000000000000000000000bdb51a04b5aa8eb6431e 

查询合约的存储slot的原始数据-cast storage

查询合约的存储slot中的原始数据。

帮助文档

Untitled 10.png

从abi生成interface-cast interface &lt;abi文件或者合约地址&gt;

使用帮助

Untitled 11.png

以WBNB为例

在https://bscscan.com/address/0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c#code中复制abi并保存到wbnb.abi文件中,使用下列命令生成接口。

讯享网cast interface wbnb.abi 

Untitled 12.png

也可以直接跟某个地址

(base) ➜ cast_basic echo $WETH 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 cast interface $WETH 

Untitled 13.png

编码解码-cast —to-xxx系统函数

讯享网cast --to-hex cast --to-dec cast --to-wei cast --to-uint 如cast --to-uint  ether 将10000转成ether的单位。 cast --to-bytes32 cast --to-ascii cast --from-wei cast --format-bytes32-string 

四. anvil使用

直接运行效果

Untitled 14.png

模拟从主网fork-casat —fork-url=$ETH_RPC_URL

使用fork-casat —fork-url=$ETH_RPC_URL可以模拟主网

Untitled 15.png

anvil 常用的命令参数

—accounts=账户的数量

—balance=每个账户的余额

—fork-block-number=区块高度

特殊的RPC方法-anvil*等同于hardhat*

anvil_impersonateAccount

anvil_setStorageAt

五. forge-智能合约开发框架

5.1 初始化项目-forge init

forge init &lt;dir_name&gt;

forge init —template &lt;template_path&gt; &lt;dir_name&gt;

Untitled 16.png

看下当前目录的结构

(base) ➜ forge_basic tree -L 2 . └── hello-foundry ├── foundry.toml ├── lib ├── script ├── src └── test 

配置设置

讯享网# 打印所有的配置 forge config # 打印基础的配置 forge config --basic # 生成新的基础配置 forge config &gt; foundry.toml 

Untitled 17.png

5.2 编译-forge build

对应的编译命令为

forge build forge build -w 实时写代码,实时编译 

&lt;aside&gt; 😀 通常会在tmux中开两个pane。 第一个pane用于查看实时编码情况,使用-w实时监控; 第二个pane中编写代码,每次修改完代码后,保存后,第一个panel就会实时显示编译是否通过。

&lt;/aside&gt;

5.3 自动化测试-forge test

讯享网# 可以使用使用-v级别、-vv级别、-vvv级别进行日志的打印 forge test -v /-vv / -vvv # 使用-w进行监视模式 forge test -v /-vv / -vvv -w 使用监视模式 

测试分类

  • 简单测试
  • fuzz
  • 不变量测试

有个牛逼的功能。标准库里有个vm实例,可以通过vm改变虚拟机的状态。

5.4 日志打印

日志打印通常有两种方法:

  1. console模块。如console2.log(”hello world”)
  2. emit log方法。如emit log(”hello world”);

注意,使用打日志的方法的方法时,如果使用forge test无法展示打印的日志,记得要—vvv以上才能打印出来,一个v时显示不出来

emit log(”hello world”);

使用console2.log(”hello world”);也是同样的效果。

Untitled 18.png

5.5 cheatcode修改vm状态

cheatcode,可以在test合约中使用vm变量修改vm的状态。

  • vm.warp() 修改vm中的block.timestamp变量
  • vm.roll() 修改vm中的block.number变量
  • vm.prank(address) 改变下一次调用的msg.sender,只改变下一次调用,其他的调用会恢复回来。

    如果后面的调用也一直保持修改,使用vm.startPrank(alice); vm.stopPrank();

  • deal(address who, uint256 newBalance) 改变who地址的余额。

vm.warp-修改timestamp示例

vm.warp(); emit log_uint(block.timestamp); 

Untitled 19.png

vm.startPrank-修改msg.sender示例

vm.startPrank(alice);

vm.stopPrank();

讯享网// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; import &quot;forge-std/Test.sol&quot;; import &quot;https://www.learnblockchain.cn/src/Counter.sol&quot;; contract CounterTest is Test { Counter public counter; address public alice; Helper public h; function setUp() public { counter = new Counter(); alice = address(1); h = new Helper(); counter.setNumber(0); } function testVm() public { console2.log(&quot;before cheatcode:&quot;, h.whoCalled()); vm.startPrank(alice); console2.log(&quot;after cheatcode:&quot;, h.whoCalled()); vm.stopPrank(); } function testIncrement() public { counter.increment(); assertEq(counter.number(), 1); } function testSetNumberOne() public { counter.setNumber(1); assertEq(counter.number(), 1); } function testSetNumber(uint256 x) public { counter.setNumber(x); assertEq(counter.number(), x); } } contract Helper { function whoCalled() public view returns(address) { return msg.sender; } } 

Untitled 20.png

vm.deal修改balance示例

vm.deal(alice, 1 ether) //改变alice地址的原生代币的余额为1 ether

Untitled 21.png

vm.rollFork() 到指定的区块高度。

function testVmFork() public { string memory MAINNET_RPC_URL = &quot;https://eth-mainnet.g.alchemy.com/v2/*l&quot;; uint256 forkId = vm.createFork(MAINNET_RPC_URL); vm.selectFork(forkId); console2.log(&quot;cur blocknum:&quot;, block.number); vm.rollFork(); console2.log(&quot;after blocknum:&quot;, block.number); } 

Untitled 22.png

vm.ffi 调用外部命令

使用vm.ffi时,在启动forge test时,需要添加 —ffi 参数。如

讯享网forge test -vvv -w --fork-url=$ETH_RPC_URL --ffi 

测试代码

function testffi() public { // 使用keccak256函数计算出hash1 string memory aMessage = &quot;abc&quot;; bytes32 hash1 = keccak256(abi.encodePacked(aMessage)); console2.logBytes32(hash1); // 使用vm.ffi计算出hash2 string[] memory cmds = new string[](3); cmds[0] = &quot;cast&quot;; cmds[1] = &quot;keccak&quot;; cmds[2] = aMessage; bytes memory ffiResult = vm.ffi(cmds); bytes32 hash2 = abi.decode(ffiResult, (bytes32)); console2.logBytes32(hash2); // 比较hash1和hash2是相同的。 assertEq(hash1, hash2); } 

Untitled 23.png

5.6 forge snapshot-快照功能

为每个测试用例的gas使用创建快照。主要用于在开发过程中对gas费的优化。

常与forge snapshot —diff 一起使用,-diff 参数会与上次的快照对比gas费的对比。

六.代码示例

6.1 如何修改ERC20代币的余额呢?

在5.5中,可以通过vm.deal来修改原生代币的余额,那么在编写测试用例时,怎样才能修改ERC20代币的余额呢?可以一起通过编写一个ERC20的代币,并使用foundry来修改ERC20代币的余额的测试用例。

yarn 安装@openzeppelin/contracts

讯享网yarn add @openzeppelin/contracts 

配置config,foundry.toml文件,将 lib中加入node_modules

libs = [&#039;lib&#039;,&#039;node_modules&#039;] 

使用forge remappings 查看当前的remappings

讯享网forge remappings &gt;remappings.txt 

将当前remappings保存到remappings.txt文件中,

@openzeppelin/=node_modules/@openzeppelin/ ds-test/=lib/forge-std/lib/ds-test/src/ forge-std/=lib/forge-std/src 

&lt;aside&gt; 🤣 如果foundry.toml文件中的libs=[’lib’] 没有包含node_modules的话,使用forge remappings 产生的remappings.txt就不会包含@openzeppelin这一行了。

&lt;/aside&gt;

使用标准的cheatcode函数deal

讯享网deal(address(dai), alice, 10000e18); assertEq(dai.balanceOf(alice), 10000e18); 

完整的演示代码

contract CounterTest is Test { Counter public counter; address public alice; Helper public h; IERC20 public dai; function setUp() public { counter = new Counter(); alice = address(1); h = new Helper(); counter.setNumber(0); dai = IERC20(0x6BE89094C44Da98b954EedeACd0F); } function testDaiDeal() public { console2.log(&quot;before deal, Alice Dai balance is&quot;,2); deal(address(dai), alice, 1001 ether); console2.log(&quot;after deal, Alice Dai balance is&quot;, alice.balance); } 

如果使用forge test -vvv -w 时,可以看到测试不会通过,测试会失败,出错内容为&quot;EvmError: Revert”,如下所示

Untitled 25.png

出错的原因是,因为dai合约没有在测试环境中部署。如果不想部署dai合约,我们可以通过fork-url的方式直接使用主网的 dai合约。

使用主网的dai合约测试的话,使用forge test -vvv -w -fork-url=$ETH_RPC_URL ,fork主网到本地进行测试。使用该命令就可以测试成功

Untitled 26.png

6.2. 如何在代码中进行fork-url

上面fork-url时,是直接通过forge调用的参数传递进去的,有没有办法在代码直接进行fork-url?

如果在代码中可以实现fork-url的话,我们就可以直接在代码针对不同的测试网络编写不同的测试用例,在测试用例中就可以覆盖全网络。

通过vm.envAddress函数可以从 vm中读取环境变量

vm.envAddress(string calldata, string calldata) 取得vm中的地址。

在代码中进行fork的主要代码

讯享网string memory rpc = vm.envString(&quot;ETH_RPC_URL&quot;); uint256 mainnet = vm.createFork(rpc); vm.selectFork(mainnet); 
IERC20 public dai; function setUp() public { counter = new Counter(); alice = address(1); h = new Helper(); counter.setNumber(0); // dai = IERC20(0x6BE89094C44Da98b954EedeACd0F); dai = IERC20(vm.envAddress(&quot;DAI&quot;)); console2.log(&quot;DAI address:&quot;, address(dai)); } function testDaiDeal() public { string memory rpc = vm.envString(&quot;ETH_RPC_URL&quot;); uint256 mainnet = vm.createFork(rpc); vm.selectFork(mainnet); console2.log(&quot;before deal, Alice Dai balance is&quot;, alice.balance); deal(address(dai), alice, 1001 ether); console2.log(&quot;after deal, Alice Dai balance is&quot;, alice.balance); } 

参考

https://book.getfoundry.sh/ https://www.youtube.com/watch?v=EXYeltwvftw&t=6s https://sig.eth.samczsun.com/

讯享网 <div id="md_view"> <p><img src="https://img.learnblockchain.cn/attachments/2022/09/a2b2gA9X63218bb03c553.png!/scale/40" alt="Untitled.png" /> 

本文列举了foundry中常用的命令,方便以后查询使用。

  • 全面支持solidity,可有效减少上下文切换

    与hardhat+ethers组合工具相比,hardhat+ethers合约使用solidity,而部署测试等使用 js或者ts。而对于foundry工具,合约、部署、测试等都使用solidity,不需要在多种编程语言之间进行切换。

  • 功能更齐全。如cast命令可以直接从etherscan下载源代码,可以直接从abi 生成interface等功能。
  • 运行速度更快。

官方网站:getfoundry.sh

在mac环境下,使用下面命令进行安装

 

foundry系列的工具,主要包含三大组件,分别对应不同的功能,下面会每个组件依次试用。

  • forge:主要用来开发、编译、部署合约。
  • cast:执行以太坊 RPC 调用的命令行工具
  • anvil:本地模拟节点环境,类似于ganache-cli的功能。

<aside> 😀 我的 ETH alchemy的RPC接点 https://eth-mainnet.g.alchemy.com/v2/*

export ETH_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/

</aside>

cast 是 Foundry 用于执行以太坊 RPC 调用的命令行工具。您可以进、!

cast与web3交互的小工具,即使不是代码开发的人员也会经常使用该工具与链上数据进行查询等交互。

cast rpc eth_blockNumber --rpc-url=$ETH_RPC_URL

<aside> 😀 cast支持环境变量ETH_RPC_URL,将RPC节点设置到环境变量ETH_RPC_URL中。 对带有--rpc-url的参数的cast命令中,可直接从环境变量中直接读取,不需要在命令中体现。

</aside>

讯享网

Untitled 1.png

 
讯享网
 

🤣 jq工具的使用

jq 一个灵活的轻量级命令行JSON处理器,jq 用于处理JSON输入,将给定过滤器应用于其JSON文本输入并在标准输出上将过滤器的结果生成为JSON。

  1. 下载https://github.com/stedolan/jq/releases
  2. 移动到 /usr/local/bin,并命名成jq,设置成可执行属性。

pretty-calldata 命令会取出 <十六进制数据>中的前4个字节,从在线网站的数据库(https://sig.eth.samczsun.com/)中比对4字节的selector对应的函数原型,并将 <十六进制数据>中的后面部分的数据按照函数原型进行格式化输出。

讯享网

可以通过cast 4byte <十六进制数据> 在查询函数selector对应的函数原型。

 

Untitled 2.png

讯享网

cast run命令

defi直接价格操纵经典案例-tcrToken被黑事件中的交易为例,可参考https://learnblockchain.cn/article/4491

对应的交易为0x81e9918e248d14d78ff7bfd9f456c6ded14fdfb69db

 

使用帮助

讯享网

创建钱包

通过cast wallet new 创建新的钱包

 

直接跟目录名,将钱包保存到keystore目录中

讯享网

Untitled 4.png

签名-cast wallet sign

Untitled 5.png ENS功能-cast resolve-name和cast lookup-address

 

Untitled 6.png

在使用查看源代码功能之前,需要设置ETHERSCAN_API_KEY的环境变量

讯享网

WETH 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2et

 

查看源代码-cast etherscan-source

cast etherscan-source $WETH 查看$WETH的源代码。

使用-d参数,将结果保存到指定目录下。

讯享网

Untitled 7.png

调用合约函数-cast call

 

Untitled 8.png

cast index 根据KEY_TYPE的类型和KEY,及SLOT_NUMBER计算出。

帮助说明

Untitled 9.png

问题:计算账户在$WETH token中的余额,可以使用两种方式取得。

  • 常规函数调用方式
  • 读取合约slot存储方式
    1. 常规函数调用方式

    采用合约函数调用的方式,可以看到该账户下有bdb51a04b5aa8eb6431e 个WETH.

    讯享网
  1. 读取合约slot存储方式

    先根据WETH的源代码,分析得到balanceOf状态变量位于第3个slot,如何获得源代码?可以通过 命令来获得。源代码如下:

     

    通过slot来读取

    讯享网

查询合约的存储slot中的原始数据。

帮助文档

Untitled 10.png

使用帮助

Untitled 11.png

以WBNB为例

在https://bscscan.com/address/0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c#code中复制abi并保存到wbnb.abi文件中,使用下列命令生成接口。

 

Untitled 12.png

也可以直接跟某个地址

讯享网

Untitled 13.png

 

直接运行效果

Untitled 14.png

模拟从主网fork-casat —fork-url=$ETH_RPC_URL

使用fork-casat —fork-url=$ETH_RPC_URL可以模拟主网

Untitled 15.png

anvil 常用的命令参数

—accounts=账户的数量

—balance=每个账户的余额

—fork-block-number=区块高度

特殊的RPC方法-anvil*等同于hardhat*

anvil_setStorageAt

forge init <dir_name>

forge init —template <template_path> <dir_name>

Untitled 16.png

看下当前目录的结构

讯享网

配置设置

 

Untitled 17.png

对应的编译命令为

讯享网

<aside> 😀 通常会在tmux中开两个pane。 第一个pane用于查看实时编码情况,使用-w实时监控; 第二个pane中编写代码,每次修改完代码后,保存后,第一个panel就会实时显示编译是否通过。

</aside>

 

测试分类

  • 简单测试
  • fuzz
  • 不变量测试

有个牛逼的功能。标准库里有个vm实例,可以通过vm改变虚拟机的状态。

日志打印通常有两种方法:

  1. console模块。如。
  2. emit log方法。如emit log(”hello world”);

注意,使用打日志的方法的方法时,如果使用无法展示打印的日志,记得要以上才能打印出来,一个v时显示不出来

emit log(”hello world”);

使用也是同样的效果。

Untitled 18.png

cheatcode,可以在test合约中使用vm变量修改vm的状态。

  • vm.warp() 修改vm中的变量
  • vm.roll() 修改vm中的变量
  • vm.prank(address) 改变调用的msg.sender,只改变下一次调用,其他的调用会恢复回来。

    如果后面的调用也一直保持修改,使用

  • deal(address who, uint256 newBalance) 改变who地址的余额。
讯享网

Untitled 19.png

vm.startPrank(alice);

vm.stopPrank();

 

Untitled 20.png

vm.deal(alice, 1 ether) //改变alice地址的原生代币的余额为1 ether

Untitled 21.png

讯享网

Untitled 22.png

使用vm.ffi时,在启动forge test时,需要添加 —ffi 参数。如

 

测试代码

讯享网

Untitled 23.png

为每个测试用例的gas使用创建快照。主要用于在开发过程中对gas费的优化。

常与 一起使用,-diff 参数会与上次的快照对比gas费的对比。

在5.5中,可以通过vm.deal来修改原生代币的余额,那么在编写测试用例时,怎样才能修改ERC20代币的余额呢?可以一起通过编写一个ERC20的代币,并使用foundry来修改ERC20代币的余额的测试用例。

yarn 安装@openzeppelin/contracts

 

配置config,foundry.toml文件,将 lib中加入

讯享网

使用forge remappings 查看当前的remappings

 

将当前remappings保存到remappings.txt文件中,

讯享网

<aside> 🤣 如果foundry.toml文件中的libs=[’lib’] 没有包含node_modules的话,使用forge remappings 产生的remappings.txt就不会包含@openzeppelin这一行了。

</aside>

使用标准的cheatcode函数deal

 

完整的演示代码

讯享网

如果使用forge test -vvv -w 时,可以看到测试不会通过,测试会失败,出错内容为"EvmError: Revert”,如下所示

Untitled 25.png

出错的原因是,因为。如果不想部署dai合约,我们可以通过的方式直接使用主网的 dai合约。

使用主网的dai合约测试的话,使用 ,fork主网到本地进行测试。使用该命令就可以。

Untitled 26.png

上面fork-url时,是直接通过forge调用的参数传递进去的,有没有办法在代码直接进行fork-url?

如果在代码中可以实现fork-url的话,我们就可以直接在代码针对不同的测试网络编写不同的测试用例,在测试用例中就可以覆盖全网络。

通过vm.envAddress函数可以从 vm中读取环境变量

vm.envAddress(string calldata, string calldata) 取得vm中的地址。

在代码中进行fork的主要代码

 
讯享网

https://book.getfoundry.sh/ https://www.youtube.com/watch?v=EXYeltwvftw&t=6s https://sig.eth.samczsun.com/

小讯
上一篇 2025-04-19 15:14
下一篇 2025-05-17 12:51

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/155038.html