前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Foundry的基本使用总结

Foundry的基本使用总结

作者头像
Tiny熊
发布2022-11-07 11:04:51
2.7K0
发布2022-11-07 11:04:51
举报
文章被收录于专栏:深入浅出区块链技术

本文作者:小驹[1]

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

一. 为什么要用 foundry

  • 全面支持 solidity,可有效减少上下文切换 与 hardhat+ethers 组合工具相比,hardhat+ethers 合约使用 solidity,而部署测试等使用 js 或者 ts。而对于 foundry 工具,合约、部署、测试等都使用 solidity,不需要在多种编程语言之间进行切换。
  • 功能更齐全。如 cast 命令可以直接从 etherscan 下载源代码,可以直接从 abi 生成 interface 等功能。
  • 运行速度更快。

二. 软件安装方法

官方网站:getfoundry.sh[2]

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

代码语言:javascript
复制
curl -L https://foundry.paradigm.xyz | bash
source ~/.zshrc
# 每次执行foundryup时,都会下载最新的cast,anvil,forge程序
foundryup

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

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

三. cast 使用

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

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

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

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

cast rpc eth_blockNumber --rpc-url=$ETH_RPC_URL

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

3.1 查询功能

查询区块高度-cast rpc eth_blockNumber

代码语言:javascript
复制
cast rpc eth_blockNumber --rpc-url=$ETH_RPC_URL
"0xebc18f"
(base) ➜  ~ cast --to-dec "0xebc18f"
15450511
(base) ➜  ~ cast --to-dec 0xebc18f
15450511

查询区块信息-cast block

代码语言:javascript
复制

(base) ➜  ~ cast block 15450511 --rpc-url=$ETH_RPC_URL

baseFeePerGas        18648783904
difficulty           12266510444604275
extraData            0x706f6f6c696e2e636f6d21bb45000ef0fc7e9d
gasLimit             29941438
gasUsed              28701300

transactions:        [
	0x1ac18cdb12a6cb7022823fef4e2bc64fa959352af58507e057fc27f62d1e23a7
	0x1b0032cb42ade1add87a25f367b4142ebe627771abc936f2a6f403bcd50e6dc5
	0x28afc8b0659d88ffb03b803b01eb573690b6e3b70a0c1cf941d7f6fafc146465

查询交易信息-cast tx <交易 hash>

代码语言:javascript
复制
(base) ➜  ~ cast tx 0xd38950f391b91fef3daaf516d86470a1552461539bdba5ace230b942d5237974 --rpc-url=$ETH_RPC_URL

blockHash            0xd73fb0230f3ab6e8a8c9ba5698c1ec7beb5aa23175e1231560b5d507b748a7ea
blockNumber          15450511
from                 0x796ed889d874dEeE8fE495F6c245765cf7db193B
gas                  96677
gasPrice             19654542987
hash                 0xd38950f391b91fef3daaf516d86470a1552461539bdba5ace230b942d5237974
input                0xa0712d680000000000000000000000000000000000000000000000000000000000000002
nonce                0
r                    0x31c9c3e6d7cd7058025a4b7cf2c17355ac856902c20fdff6b83d2c134d66ea2f
s                    0x1775d3a1002467e05cbabc23219e18b27e9ac29dd0dbdafc165bbab052f7ba23
to                   0xc93f78f08c7E9526C78Da56Cba1DEE8287baCb27
transactionIndex     4
v                    1
value                0

交易回执查询-cast receipt <receipt_hash>

代码语言:javascript
复制
base) ➜  ~ cast receipt 0xd38950f391b91fef3daaf516d86470a1552461539bdba5ace230b942d5237974 --rpc-url=$ETH_RPC_URL

blockHash               0xd73fb0230f3ab6e8a8c9ba5698c1ec7beb5aa23175e1231560b5d507b748a7ea
blockNumber             15450511
contractAddress
cumulativeGasUsed       564786
effectiveGasPrice       19654542987
gasUsed                 86319
logs                    [{"address":"0xc93f78f08c7e9526c78da56cba1dee8287bacb27","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000000000000000000000000000

使用 --json 以json格式返回数据,使用管道输入给jq进行处
cast receipt 0xd38950f391b91fef3daaf516d86470a1552461539bdba5ace230b942d5237974 --rpc-url=$ETH_RPC_URL --json | jq

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

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

查询 calldata 数据-cast pretty-calldata <十六进制数据>

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

代码语言:javascript
复制

查看input数据
(base) ➜  ~ cast tx 0x3574c7c9b34df46d7476c5a8e9fb48b2bf007df7d5d021ef9aa79983f4b13f92 --rpc-url=$ETH_RPC_URL input
0xa9059cbb0000000000000000000000007f1949e62203a83ad6e6be0a819f93e580054f9d000000000000000000000000000000000000000000038e8f7792d79767800000

(base) ➜  ~ cast pretty-calldata 0xa9059cbb0000000000000000000000007f1949e62203a83ad6e6be0a819f93e580054f9d000000000000000000000000000000000000000000038e8f7792d79767800000

 Possible methods:
 - transfer(address,uint256)
 ------------



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

代码语言:javascript
复制

# 查询0xa9059cbb selector对应的函数原型
(base) ➜  ~ cast 4byte 0xa9059cbb
transfer(address,uint256)

# 使用keccak计算函数原型对应的hash,可以发现hash的前4个字节就是selector
(base) ➜  ~ cast keccak "transfer(address,uint256)"
0xa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b

(base) ➜  ~ cast sig "transfer(address,uint256)"
0xa9059cbb

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

代码语言:javascript
复制

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

3.2 交易模拟-cast run

cast run 命令

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

对应的交易为0x81e9918e248d14d78ff7b697355fd9f456c6d7881486ed14fdfb69db16631154[5]

代码语言:javascript
复制
(base) ➜ ~ cast run 0x81e9918e248d14d78ff7b697355fd9f456c6d7881486ed14fdfb69db16631154

3.3 钱包相关功能-cast wallet

使用帮助

代码语言:javascript
复制
(base) ➜  ~ cast wallet -h
cast-wallet
Wallet management utilities.

USAGE:
    cast wallet <SUBCOMMAND>

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 创建新的钱包

代码语言:javascript
复制
(base) ➜  ~ cast wallet new
Successfully created new keypair.
Address: 0x382B0Db462165Bc1b78B355eBB747E2F378bC711

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

代码语言:javascript
复制
(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`\nPublic Address of the key: 0xb18A7BC0c376CB3be07CCC883900b61d8e33ce8B

签名-cast wallet sign

ENS 功能-cast resolve-name 和 cast lookup-address

代码语言:javascript
复制
(base) ➜  cast_basic cast resolve-name vatalik.eth
0x7d66bD3dA15e079495989dc8139379784146afeD
(base) ➜  cast_basic cast lookup-address 0x7d66bD3dA15e079495989dc8139379784146afeD
Error:
ens name not found: 7d66bd3da15e079495989dc8139379784146afed.addr.reverse

3.4 合约相关功能

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

代码语言:javascript
复制
export ETHERSCAN_API_KEY=NZMQ7KC5CD5BND19KMBQFA3BI3QJUTG53V

WETH 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2et

代码语言:javascript
复制
export WETH=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

查看源代码-cast etherscan-source

cast etherscan-source

WETH 查看

WETH 的源代码。

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

代码语言:javascript
复制
(base) ➜  cast_basic cast etherscan-source $WETH -d weth_source
(base) ➜  cast_basic vi weth_source/WETH9/WETH9.sol

调用合约函数-cast call

代码语言:javascript
复制
cast call $WETH "balanceOf(address)" 0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e

(base) ➜  cast_basic cast --to-dec 0x00000000000000000000000000000000000000000000bdb51a04b5aa8eb6431e

895868000762793410577182

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

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

帮助说明

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

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

常规函数调用方式

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

代码语言:javascript
复制
(base) ➜  cast_basic cast call $WETH  "balanceOf(address)" 0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e
0x00000000000000000000000000000000000000000000bdb51a04b5aa8eb6431e

读取合约 slot 存储方式

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

代码语言:javascript
复制
pragma solidity ^0.4.18;

  contract WETH9 {
      string public name     = "Wrapped Ether";
      string public symbol   = "WETH";
      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 => uint)                       public  balanceOf;
      mapping (address => mapping (address => uint))  public  allowance;

      function() public payable {
          deposit();
      }

通过 slot 来读取

代码语言:javascript
复制
# 先计算出KEY_TYPE为address,KEY为0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e,slot为3,所对应的存储位置。
(base) ➜  cast_basic cast index address  0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e 3
0x1f8193c3f94e8840dc3a6dfc0bc012432d338ef33c4f3e4b3aca0d6d3c5a09b6

# 取出对应存储位置的原始数据,因为为address=>int,所以取出来就没int
(base) ➜  cast_basic cast storage $WETH  0x1f8193c3f94e8840dc3a6dfc0bc012432d338ef33c4f3e4b3aca0d6d3c5a09b6
0x00000000000000000000000000000000000000000000bdb51a04b5aa8eb6431e

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

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

帮助文档

从 abi 生成 interface-cast interface <abi 文件或者合约地址>

使用帮助

以 WBNB 为例

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

代码语言:javascript
复制
cast interface wbnb.abi

也可以直接跟某个地址

代码语言:javascript
复制
(base) ➜  cast_basic echo $WETH
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

cast interface $WETH

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

代码语言:javascript
复制
cast --to-hex
cast --to-dec

cast --to-wei
cast --to-uint  如cast --to-uint 100000 ether 将10000转成ether的单位。

cast --to-bytes32
cast --to-ascii

cast --from-wei
cast --format-bytes32-string

四. anvil 使用

直接运行效果

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

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

anvil 常用的命令参数

—accounts=账户的数量

—balance=每个账户的余额

—fork-block-number=区块高度

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

anvil_impersonateAccount

anvil_setStorageAt

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

5.1 初始化项目-forge init

forge init <dir_name>

forge init —template <template_path> <dir_name>

看下当前目录的结构

代码语言:javascript
复制
(base) ➜  forge_basic tree -L 2
.
└── hello-foundry
    ├── foundry.toml
    ├── lib
    ├── script
    ├── src
    └── test

配置设置

代码语言:javascript
复制
# 打印所有的配置
forge config

# 打印基础的配置
forge config --basic

# 生成新的基础配置
forge config > foundry.toml

5.2 编译-forge build

对应的编译命令为

代码语言:javascript
复制
forge build
forge build -w 实时写代码,实时编译

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

5.3 自动化测试-forge test

代码语言:javascript
复制
# 可以使用使用-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”);也是同样的效果。

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 示例
代码语言:javascript
复制
vm.warp(1641070800);
emit log_uint(block.timestamp);

vm.startPrank-修改 msg.sender 示例

vm.startPrank(alice);

vm.stopPrank();

代码语言:javascript
复制
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;

import "forge-std/Test.sol";
import "../src/Counter.sol";

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("before cheatcode:", h.whoCalled());
       vm.startPrank(alice);
       console2.log("after cheatcode:", 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;
    }
}

vm.deal 修改 balance 示例

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

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

代码语言:javascript
复制
function testVmFork() public {
        string memory MAINNET_RPC_URL = "https://eth-mainnet.g.alchemy.com/v2/*******l";
        uint256 forkId = vm.createFork(MAINNET_RPC_URL);
        vm.selectFork(forkId);
        console2.log("cur blocknum:", block.number);
        vm.rollFork(15531500);
        console2.log("after blocknum:", block.number);
    }

vm.ffi 调用外部命令

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

代码语言:javascript
复制
forge test -vvv -w --fork-url=$ETH_RPC_URL --ffi

测试代码

代码语言:javascript
复制
function testffi() public {
        // 使用keccak256函数计算出hash1
        string memory aMessage = "abc";
        bytes32 hash1 = keccak256(abi.encodePacked(aMessage));
        console2.logBytes32(hash1);

        // 使用vm.ffi计算出hash2
        string[] memory cmds = new string[](3 "] memory cmds = new string[");
        cmds[0] = "cast";
        cmds[1] = "keccak";
        cmds[2] = aMessage;

        bytes memory ffiResult = vm.ffi(cmds);
        bytes32 hash2 = abi.decode(ffiResult, (bytes32));
        console2.logBytes32(hash2);

        // 比较hash1和hash2是相同的。
        assertEq(hash1, hash2);
    }

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

代码语言:javascript
复制
yarn add @openzeppelin/contracts

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

代码语言:javascript
复制
libs = ['lib','node_modules']

使用 forge remappings 查看当前的 remappings

代码语言:javascript
复制
forge remappings >remappings.txt

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

代码语言:javascript
复制
@openzeppelin/=node_modules/@openzeppelin/
ds-test/=lib/forge-std/lib/ds-test/src/
forge-std/=lib/forge-std/src

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

使用标准的 cheatcode 函数 deal

代码语言:javascript
复制
deal(address(dai), alice, 10000e18);
assertEq(dai.balanceOf(alice), 10000e18);

完整的演示代码

代码语言:javascript
复制
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(0x6B175474E89094C44Da98b954EedeAC495271d0F);
    }

    function testDaiDeal() public {
        console2.log("before deal, Alice Dai balance is",2);
        deal(address(dai), alice, 1001 ether);
        console2.log("after deal, Alice Dai balance is", alice.balance);
}

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

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

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

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

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

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

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

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

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

代码语言:javascript
复制
string memory rpc = vm.envString("ETH_RPC_URL");
uint256 mainnet = vm.createFork(rpc);
vm.selectFork(mainnet);

代码语言:javascript
复制
IERC20 public dai;

    function setUp() public {
       counter = new Counter();
       alice = address(1);
       h = new Helper();
       counter.setNumber(0);
       // dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
       dai = IERC20(vm.envAddress("DAI"));
       console2.log("DAI address:", address(dai));
    }

    function testDaiDeal() public {
        string memory rpc = vm.envString("ETH_RPC_URL");
        uint256 mainnet = vm.createFork(rpc);
        vm.selectFork(mainnet);
        console2.log("before deal, Alice Dai balance is", alice.balance);
        deal(address(dai), alice, 1001 ether);
        console2.log("after deal, Alice Dai balance is", alice.balance);
}

参考

https://book.getfoundry.sh/

https://www.youtube.com/watch?v=EXYeltwvftw&t=6s

https://sig.eth.samczsun.com/

参考资料

[1]

小驹: https://learnblockchain.cn/people/9625

[2]

getfoundry.sh: http://getfoundry.sh

[3]

https://sig.eth.samczsun.com/: https://sig.eth.samczsun.com/

[4]

https://learnblockchain.cn/article/4491: https://learnblockchain.cn/article/4491

[5]

0x81e9918e248d14d78ff7b697355fd9f456c6d7881486ed14fdfb69db16631154: https://cn.etherscan.com/tx/0x81e9918e248d14d78ff7b697355fd9f456c6d7881486ed14fdfb69db16631154

[6]

https://bscscan.com/address/0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c#code: https://bscscan.com/address/0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c#code

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-09-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 深入浅出区块链技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一. 为什么要用 foundry
  • 二. 软件安装方法
  • 三. cast 使用
    • 3.1 查询功能
      • 3.2 交易模拟-cast run
        • 3.3 钱包相关功能-cast wallet
          • 3.4 合约相关功能
            • 查询合约的 slot 的存储位置-cast index
            • 四. anvil 使用
            • 五. forge-智能合约开发框架
              • 5.1 初始化项目-forge init
                • 5.2 编译-forge build
                  • 5.3 自动化测试-forge test
                    • 5.4 日志打印
                      • 5.5 cheatcode 修改 vm 状态
                        • vm.startPrank-修改 msg.sender 示例
                          • 5.6 forge snapshot-快照功能
                          • 六.代码示例
                            • 6.1 如何修改 ERC20 代币的余额呢?
                              • 6.2. 如何在代码中进行 fork-url
                              • 参考
                                • 参考资料
                                相关产品与服务
                                区块链
                                云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。
                                领券
                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档