如何与智能合约进行交互

  • QuickNode
  • 发布于 2024-04-07 19:11
  • 阅读 12

本文是一个详细的指南,介绍如何与Ethereum智能合约进行交互。内容覆盖了智能合约的基本概念、应用程序二进制接口(ABI)、读取和写入功能的区别以及不同的以太坊单位。文章还提供了使用Etherscan、Ethers.js和Web3.js的具体操作步骤,适合开发者学习和实践。

概述

无论你是想将区块链功能集成到应用程序中的开发人员,还是对直接与智能合约进行交互感到好奇,本指南将为你提供有效与以太坊智能合约交互所需的知识和工具。

你将做什么

通过遵循本指南,你将:

你将需要的内容

在深入智能合约的世界之前,确保你拥有以下内容:

依赖项 版本
ethers ^6.10.0
web3 ^4.4.0

理解智能合约

ABI(应用程序二进制接口)

ABI 对于以太坊智能合约至关重要,因为它充当了接口。它基本上告诉你的应用程序如何格式化对智能合约的调用以及如何读取返回的数据。可以将其视为你的代码与区块链之间的接口,以一种你的应用程序能够理解的方式详细说明智能合约的函数和变量。

以下示例 ABI 详细说明了智能合约中的 balanceOfdeposit 函数。

示例 ABI

;[\
    {\
        constant: true,\
        inputs: [{ name: '', type: 'address' }],\
        name: 'balanceOf',\
        outputs: [{ name: '', type: 'uint256' }],\
        payable: false,\
        stateMutability: 'view',\
        type: 'function',\
    },\
    {\
        constant: false,\
        inputs: [],\
        name: 'deposit',\
        outputs: [],\
        payable: true,\
        stateMutability: 'payable',\
        type: 'function',\
    },\
]

如果合约已在 Etherscan 上验证,你可以在 代码 部分获取合约的 ABI。

以太坊节点端点

读取/写入函数

智能合约由代码组成,并可以包含具有读取和写入能力的函数(类似于其他编程语言中的函数)。函数中的一些读取能力示例包括从你自己的智能合约读取状态(例如,检索映射值或结构)或从其他智能合约读取状态。与写入函数不同,这些读取操作不需要在网络上提交事务。

另一方面,写入函数(更改区块链状态的函数;例如,将代币转移到另一个地址)只能通过提交适当的交易格式和负载数据的交易(起源于 EOA 或智能合约)到网络来完成。由于写操作包含在交易中,你必须支付 gas 费用。

单位

与智能合约交互时,你将遇到不同的以太(ETH)面额。以太的最小面额是 wei,等于 10^-18 ETH。理解这些单位对于交易非常重要,因为 gas 费用通常以 gwei 表示,而交易值通常以 wei 或其倍数指定。

单位 wei wei 值 gwei 值 Ether 值
Wei 1 1 Wei 1e-9 Gwei 1e-18 Ether
Gwei 1,000,000,000 1e+9 Wei 1 Gwei 1e-9 Ether
Ether 1,000,000,000,000,000,000 1e+18 Wei 1e+9 Gwei 1 Ether

项目先决条件

QuickNode 多链水龙头

你需要一些 ETH 来确认交易并将其中一些转换为 WETH。

转到 QuickNode 多链水龙头,连接你的钱包或粘贴你的钱包地址。你需要选择 以太坊 链和 Sepolia 网络,然后请求资金。请注意,以太坊主网使用 EVM 水龙头需要 0.001 ETH 的主网余额。你还可以通过推特或登录你的 QuickNode 账户获得额外的奖励!

QuickNode 以太坊端点

要与以太坊互动,你需要一个 API 端点来连接到网络。你可以使用公共节点或部署和管理自己的基础设施;然而,如果你希望获得更快的响应时间,你可以将重担交给我们。你可以在 这里 注册一个免费账户。

登录 QuickNode 后,点击 创建端点 按钮,然后选择 以太坊 链和 Sepolia 网络。请注意,这个指南中的所有过程也适用于其他基于 EVM 的链(例如 Polygon、Arbitrum)。

创建端点后,复制 HTTP 提供程序链接 并保留以备后用,因为你将在接下来的部分中需要它。

以太坊节点端点

与智能合约进行交互

要与智能合约进行交互,你可以使用各种工具和库。让我们从最简单的方法——Etherscan 开始,然后使用 Ethers.js 和 Web3.js 进行更高级的交互。

在所有方法中,我们将使用 WETH 合约的以下函数。

  • balanceOf 函数,以获取 WETH 余额信息,作为 读取 函数的示例
  • deposit 函数,将一些 ETH 转换为 WETH,作为 写入 函数的示例

为方便起见,我们将使用 以太坊 Sepolia 测试网,但在整个过程中也可以使用以太坊主网。

  • 以太坊 Sepolia 上的 WETH 合约地址:0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14
  • 以太坊主网 上的 WETH 合约地址:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

信息

WETH 代表 Wrapped ETH。WETH 与 ERC-20 标准兼容,并与 ETH 挂钩。例如,可以通过调用 WETH 合约的 deposit 函数将 1 ETH 转换为 1 WETH。也可以通过 withdraw 函数执行相反操作。

使用 Etherscan 与智能合约交互

Etherscan 是直接与 已验证 的智能合约交互的最简单和最便捷的方法。无需设置项目并编写代码。

如果智能合约未在 Etherscan 上验证,则无法使用 Etherscan 与其交互。

步骤 1: 转到 Etherscan Sepolia 区块浏览器

步骤 2: 通过搜索合约地址转到合约页面。 在本指南中,我们将使用 WETH 的地址:0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14

如何从智能合约中读取数据(Etherscan)

步骤 3: 在合约页面上,导航到 合约 选项卡,点击 读取合约

步骤 4: 点击 连接到 Web3 按钮以连接你的浏览器基于的 Web3 钱包(即 MetaMask)。

Etherscan 连接钱包

步骤 5: 点击你想要查询的读取函数。如果函数需要任何必要的输入参数,请确保输入这些参数。如果需要参数,请在输入参数后不要忘记点击 查询 按钮。

在本指南中,我们将调用 balanceOf 函数以获取我们想要的地址的代币余额。

Etherscan 读取合约

如何向智能合约写入数据(Etherscan)

步骤 6:合约 选项卡下,点击 写入合约

步骤 7: 如果尚未连接,则连接你的 Web3 钱包。

步骤 8: 点击你想要调用的写入函数。如果函数需要任何必要的输入参数,请确保输入这些参数。在本指南中,我们将调用 deposit 函数将 0.05 ETH 转换为 0.05 WETH(也称为 包装 0.05 ETH)。

虽然 wei(ETH 的最低单位)通常用于智能合约中,但 Etherscan 界面要求我们在参数字段中写入 ether 单位,而不是 wei

在输入 0.05 后,点击 写入 按钮并在你的钱包上确认交易。

MetaMask 交易屏幕

步骤 9(可选): 重复读取数据的过程以检查 balanceOf 函数的结果是否增加了 0.05 ETH

如果你的初始 WETH 余额为 0,则结果应为 50000000000000000 wei,相当于 0.05 ETH。

如在 单位 部分提到的,1 ETH 等于 1,000,000,000,000,000,000 wei(或 10^18 wei)。因此,如果将 50000000000000000 wei(或 5*10^16 wei)除以 1,000,000,000,000,000,000 wei(或 10^18),结果将是 0.05 ETH。

使用 Ethers.js 与智能合约交互

Ethers.js 是与以太坊和其他 EVM 兼容区块链交互的最流行的以太坊库之一。让我们学习如何直接使用 Ethers.js 库与智能合约进行交互。

设置项目

步骤 1: 确保你的计算机上已安装 Node.js。如果没有,请安装。

步骤 2: 创建一个新文件夹并在新创建的文件夹中初始化一个新的 Node.js 项目。

mkdir interact-ethersjs && cd interact-ethersjs
npm init --y

步骤 3:Ethers.jsdotenv 添加到你的项目中。

npm install ethers dotenv

步骤 4: 创建一个新 JavaScript 文件(例如,index-ethers.js)和一个 .env 文件。

echo > index-ethers.js
echo > .env

步骤 5: 将敏感信息(QuickNode 端点 HTTP URL 和你钱包的私钥)添加到 .env 文件中。

打开 .env 文件,并将 YOUR_QUICKNODE_ENDPOINT_HTTP_URLYOUR_WALLET_PRIVATE_KEY 替换为你的 QuickNode 端点 URL 和你钱包的私钥(用于签署交易),如:

HTTP_PROVIDER_URL="YOUR_QUICKNODE_ENDPOINT_HTTP_URL"
PRIVATE_KEY="YOUR_WALLET_PRIVATE_KEY"

步骤 6: 初始化连接并设置代码。

打开 index-ethers.js 文件,添加以下代码:

这段代码使用 Ethers.js 初始化与以太坊智能合约的连接,为后续交互(例如查询余额或通过合约的函数发起交易)做好准备。

信息

provider 是与以太坊区块链连接的抽象,允许只读访问区块链上的数据和状态。它无法签署交易或消息,因为它不持有私钥。然而,它可以将任何签名的交易广播到区块链。

signer 是持有私钥的实体,可以签署交易或消息,因此能够在区块链上执行状态更改操作。它通常用于签署和发送交易。

contract 实例通过 provider 连接到区块链以进行只读交互。当你创建 contractWithSigner 时,你基本上是用 signer(它包括私钥和 provider)重新连接相同的合约实例,使其能够对合约执行写操作(如发送交易)。

index-ethers.js

// 导入 ethers.js 库以与以太坊区块链交互
require('dotenv').config()
const ethers = require('ethers')

// QuickNode 端点和用户私钥的配置
const QUICKNODE_ENDPOINT = process.env.HTTP_PROVIDER_URL
const PRIVATE_KEY = process.env.PRIVATE_KEY

// 设置提供程序和签名者以通过 QuickNode 连接到以太坊网络
const provider = new ethers.JsonRpcProvider(QUICKNODE_ENDPOINT)
const signer = new ethers.Wallet(PRIVATE_KEY, provider)

const userAddress = signer.address

// 合约细节:在 Sepolia 测试网络上的 WETH 合约
const contractAddress = '0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14'
const contractABI = [\
    // 与合约交互的 ABI 定义\
    {\
        constant: true,\
        inputs: [{ name: '', type: 'address' }],\
        name: 'balanceOf',\
        outputs: [{ name: '', type: 'uint256' }],\
        payable: false,\
        stateMutability: 'view',\
        type: 'function',\
    },\
    {\
        constant: false,\
        inputs: [],\
        name: 'deposit',\
        outputs: [],\
        payable: true,\
        stateMutability: 'payable',\
        type: 'function',\
    },\
]

// 实例化用于与 WETH 合约交互的合约对象
const contract = new ethers.Contract(contractAddress, contractABI, provider)
const contractWithSigner = contract.connect(signer)

// 从合约读取数据
// 读取函数将在这里
// Writing to the contract
// 写入函数将在这里

如何通过 Ethers.js 从智能合约中读取数据

在我们设置连接和合约实例进行交互后,现在增加 readContract 函数。

此函数 readContract 从智能合约读取指定用户地址的 WETH 余额并将其日志记录到控制台,以 wei 和 ether 单位清晰展示。将高亮显示的函数添加到 index-ethers.js 文件中。

由于从智能合约读取数据不需要签署任何交易,因此尚未使用私钥。

只需将以下代码片段添加到文件底部。

index-ethers.js

// 从合约读取数据
async function readContract() {
    console.log('正在读取余额...')
    // 查询合约以获得指定用户地址的余额
    const balance = await contract.balanceOf(userAddress)
    // 将余额从 wei 转换为 ether 以便于阅读
    const balanceInEther = ethers.formatEther(balance)
    // 在 wei 中记录余额
    console.log(`用户的 WETH 余额(wei):${balance}`)
    // 以 ether 记录余额,提供更熟悉的计量单位
    console.log(`用户的 WETH 余额(ETH):${balanceInEther}`)
}

如何通过 Ethers.js 向智能合约写入数据

现在,是时候调用其中一个写入函数(例如,deposit())以包装一些 ETH。

将高亮显示的函数添加到 index-ethers.js 文件中。

注意,我们在定义这两个函数后都进行了调用。最后,我们再次调用 readContract 函数,以便在包装一些 ETH 后查看 WETH 余额的增加。

信息

交易可以包括各种参数,包括 gasLimitgasPricevaluenonce。请查看所有参数的 Ethers.js 文档

在本指南中,我们只使用 value 参数,用于指定与交易一起发送的以太金额(以 wei 为单位,用于可支付的函数)。Ethers.js SDK 为我们管理其他所需的值,简化了交易过程。

只需将下面的代码片段添加到文件底部。

index-ethers.js

// 向合约写入数据
async function writeContract() {
    console.log('调用 deposit 函数...')
    const transactionResponse = await contractWithSigner.deposit({
        value: ethers.parseEther('0.05'),
    })
    await transactionResponse.wait()
    console.log(`交易哈希:${transactionResponse.hash}`)
}

// 调用函数
;(async () => {
    // 首先,读取合约以获取初始状态
    await readContract()
    // 接下来,向合约写入数据并等待交易完成
    await writeContract()
    // 最后,再次读取合约以查看写操作后进行的更改
    await readContract()
})().catch(console.error)

运行代码

运行以下命令以运行 index-ethers.js 文件。

node index-ethers.js

如果一切顺利,控制台输出应类似于以下内容。可以看到,在调用 deposit 函数后,地址的 WETH 余额增加了 0.05 ether。

正在读取余额...
用户的 WETH 余额(wei):100000000000000000
用户的 WETH 余额(ETH):0.1
调用 deposit 函数...
交易哈希:0x10be646a1be093c6baf744ec436d48f6b11b649322ba358e0a9a4fbc3810fe62
正在读取余额...
用户的 WETH 余额(wei):150000000000000000
用户的 WETH 余额(ETH):0.15

使用 Web3.js 与智能合约交互

Web3.js 是一个全面的以太坊库,可启用与以太坊和其他 EVM 兼容区块链的交互。让我们探索如何使用 Web3.js 库直接与智能合约交互。

设置项目

步骤 1: 确保你的计算机上已安装 Node.js。如果没有,请安装。

步骤 2: 创建一个新文件夹并在新创建的文件夹中初始化一个新的 Node.js 项目。

mkdir interact-web3js && cd interact-web3js
npm init -y

步骤 3: 在你的项目中安装 Web3.jsdotenv

npm install web3 dotenv

步骤 4: 创建一个新的 JavaScript 文件(例如,index-web3.js)和一个 .env 文件。

echo > index-web3.js
echo > .env

步骤 5: 用你的敏感数据填充 .env 文件,包括 QuickNode 端点 HTTP URL 以及你钱包的私钥,以便能够进行交易签名。

编辑 .env 文件,将 YOUR_QUICKNODE_ENDPOINT_HTTP_URLYOUR_WALLET_PRIVATE_KEY 替换为你的实际 QuickNode 端点 URL 和你的私钥。

HTTP_PROVIDER_URL="YOUR_QUICKNODE_ENDPOINT_HTTP_URL"
PRIVATE_KEY="YOUR_WALLET_PRIVATE_KEY"

步骤 6: 在项目中准备连接和设置代码。

打开 index-web3.js 文件并添加以下代码,以通过 Web3.js 初始化与以太坊智能合约的连接,为查询或交易做好准备。

index-web3.js

// 导入 Web3.js 以进行区块链交互
require('dotenv').config()
const { Web3 } = require('web3')

// 配置用户的 QuickNode 端点和私钥
const QUICKNODE_ENDPOINT = process.env.HTTP_PROVIDER_URL
const PRIVATE_KEY = process.env.PRIVATE_KEY
const privateKeyWithPrefix = PRIVATE_KEY.startsWith('0x')
    ? PRIVATE_KEY
    : `0x${PRIVATE_KEY}`

// 通过 QuickNode 与以太坊网络建立提供程序连接
const web3Client = new Web3(QUICKNODE_ENDPOINT)

// 合约细节:用于与 Sepolia 测试网络上的 WETH 合约交互
const contractAddress = '0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14'
const contractABI = [\
    // 合约交互的 ABI 数组\
    {\
        constant: true,\
        inputs: [{ name: '', type: 'address' }],\
        name: 'balanceOf',\
        outputs: [{ name: '', type: 'uint256' }],\
        payable: false,\
        stateMutability: 'view',\
        type: 'function',\
    },\
    {\
        constant: false,\
        inputs: [],\
        name: 'deposit',\
        outputs: [],\
        payable: true,\
        stateMutability: 'payable',\
        type: 'function',\
    },\
]

// 添加账户对象
const account = web3Client.eth.accounts.wallet.add(privateKeyWithPrefix)
const userAddress = account[0].address

// 实例化用于与以太坊合约交互的合约对象
const contract = new web3Client.eth.Contract(contractABI, contractAddress)

如何通过 Web3.js 从智能合约中读取数据

在我们设置了连接和合约实例后,我们现在将添加 readContract 函数。

这个 readContract 函数从智能合约检索并记录指定用户地址的 WETH 余额,以 wei 和 ether 单位清晰展示。将高亮显示的函数添加到你的 index-web3.js 文件中。

从智能合约读取数据不需要签名交易,因此私钥在此阶段保持未使用状态。

只需将以下代码片段添加到文件底部。

index-web3.js

// 从合约读取数据
async function readContract() {
    console.log('正在读取余额...')
    // 查询合约以获得指定用户地址的余额
    const balance = await contract.methods.balanceOf(userAddress).call()
    // 将余额从 wei 转换成 ether 便于阅读
    const balanceInEther = web3Client.utils.fromWei(balance, 'ether')
    // 在 wei 中记录余额
    console.log(`用户的 WETH 余额(wei):${balance}`)
    // 以 ether 记录余额,提供更熟悉的计量单位
    console.log(`用户的 WETH 余额(ETH):${balanceInEther}`)
}

如何通过 Web3.js 向智能合约写入数据

现在,让我们实施 deposit 函数,在智能合约上执行写操作,特别是用于包装 ETH。

将此高亮显示的函数添加到你的 index-web3.js 文件中。

注意,执行写操作涉及使用私钥来签名交易。

信息

交易可以包括各种参数,包括 gasLimitgasPricevaluenonce。请查看所有参数的 Web3.js 文档

在本指南中,我们只使用 from,它定义发送交易的地址以及 value 参数,它指定与交易一起发送的以太金额(以 wei 为单位)用于可支付的函数。Web3.js SDK 为我们管理其他所需的值,简化了交易过程。

只需将下面的代码片段添加到你的文件底部。

index-web3.js

// 向合约写入数据
async function writeContract() {
    console.log('正在调用 deposit 函数...')
    const transactionResponse = await contract.methods.deposit().send({
        from: account[0].address,
        value: web3Client.utils.toWei('0.05', 'ether'),
    })
    console.log(`交易哈希:${transactionResponse.transactionHash}`)
}

// 调用函数
;(async () => {
    await readContract() // 读取初始状态
    await writeContract() // 执行写操作
    await readContract() // 读取最终状态以观察更改
})().catch(console.error)

运行代码

运行以下命令以运行 index-web3.js 文件。

node index-web3.js

预期的输出应该表示初始的 WETH 余额、存款的交易哈希,以及更新后的 WETH 余额,展示通过 Web3.js 与智能合约成功交互的情况。此交互展示了在存款操作后余额增加了 0.05 ETH。

正在读取余额...
用户的 WETH 余额(wei):0
用户的 WETH 余额(ETH):0.
正在调用 deposit 函数...
交易哈希:0x4283732f33ea2540ae6ceb5f27e0831dcd00c6ffcc6b1c12fd1432e7396ddc2b
正在读取余额...
用户的 WETH 余额(wei):50000000000000000
用户的 WETH 余额(ETH):0.05

结论

在本指南中,我们通过 Etherscan、Ethers.js 和 Web3.js 导航了与以太坊智能合约的互动,为希望深入以太坊开发的任何人提供了坚实的基础。每种方法都提供了独特的优势,从 Etherscan 的简便性到 Ethers.js 和 Web3.js 提供的灵活性和控制力。这些基础知识为高级以太坊开发奠定了基础,鼓励你继续探索和创新区块链生态系统。

如果你想查看其他指南,可以查看 Ethers.js 相关指南Web3.js 相关指南

订阅我们的 时事通讯,获取更多关于 Web3 和区块链的文章和指南。如果你有任何问题或需要进一步的帮助,欢迎加入我们的 Discord 服务器或通过下面的表单提供反馈。通过关注我们的 Twitter(@QuickNode)和我们的 Telegram 宣布频道,随时与最新动态保持同步。

我们 ❤️ 反馈!

告诉我们 如果你有任何反馈或对新主题的请求。我们很乐意听取你的意见。

  • 原文链接: quicknode.com/guides/eth...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。