入门混合主题
原文地址: Sophomore Mixed Topics
翻译: JulySong
有一些主题我们想提供一些信息,但不够详细,不值得拥有自己的水平。这个级别旨在将一堆单独的主题组合在一起,并回顾一些有助于记住的事情。
目录
提供者和签名者(Providers and Signers)
在构建智能合约接口时,您通常会遇到这两个术语 -Provider
和Signer
. 当您实际开始使用它们时,您将对它们有更好的理解,我们将尝试简要解释它们的含义。
我们知道,要向区块链读取或写入数据,我们需要通过以太坊节点进行通信。该节点包含区块链状态,允许我们读取数据。它还可以向矿工广播交易,允许我们写入数据。
请注意,如果您想将数据写入区块链,节点只需要广播交易。因为如果你只是读取已经存在的数据,矿工不需要做任何事情,他们已经完成了他们的工作。
Provider
是一个以太坊节点连接,允许您从其状态读取数据。您将使用 Provider
来执行诸如调用智能合约中的只读函数、获取账户余额、获取交易详细信息等操作。
Signer
是一个以太坊节点连接,允许您将数据写入区块链。您将使用 Signer
来执行诸如调用智能合约中的写入函数、在账户之间转移 ETH 等事情。为此,Signer
需要访问Private Key
可用于代表账户进行交易的。
此外,一个Signer
可以做任何事情Provider
。您可以同时使用Signer
进行读取和写入,但Provider
仅适用于读取数据。
默认情况下,像 Metamask 这样的钱包会将 Provider
注入您的浏览器。因此,dApp 可以使用您的 MetamaskProvider
从您的钱包连接的区块链网络中读取值。
但是,有时,您希望用户进行事务,而不仅仅是读取数据。当然,Metamask 不能只与随机网站共享您的私钥——那太疯狂了。为此,Metamask 还允许网站请求Signer
. 因此,当 dApp 尝试向区块链发送交易时,会弹出 Metamask 窗口,要求用户确认操作。
大数(BigNumbers)
在学习 Solidity 时,我们一直在阅读和使用uint256
很多东西。uint256
范围从0
到(2^256) - 1
。因此,数据类型可以容纳的最大数量uint256
是天文数字。
具体来说,最大值为uint256
:
115792089237316195423570985008687907853269984665640564039457584007913129639935
相比之下,一百万是:
1000000
显然,uint256
可以容纳非常大的数字。但这提出了一个问题。
我们通常用 Javascript 为智能合约构建接口。Javascript 的number
数据类型的上限要小得多。
具体来说,Javascript 可以容纳的数值类型的最大值只是:
9007199254740991
那甚至不接近uint256
可以容纳的东西!
因此,假设我们使用 Javascript 调用智能合约上的一个函数,该函数返回一个uint256
. 如果该数字大于 Javascript 的最大数值,这绝对是可能的,那么会发生什么?
好吧,事实证明,Javascript 无法支持这一点。因此,我们必须使用一种称为 BigNumber
的特殊类型。用于与以太坊节点交互的库 - ethers.js
并且 web3.js
- 都支持 BigNumber
.
BigNumber
是一个用 Javascript 编写的自定义类库,它引入了它自己的数学函数函数 - add
、sub
、mul
、div
等。BigNumber
与 Javascript 本身支持的数字相比,它的数字容量要大得多。
当我们在以下级别编写代码时,您会遇到通过调用诸如 and
之类的函数来完成数学运算.add()
,而不是我们所知道.mul()
的典型的+
and*
运算符 - 这是因为当我们使用 BigNumber 时,我们需要使用它的数学函数。
至于如果我们尝试使用 Javascript 数字执行此操作会发生什么,我们很容易上溢或下溢。这意味着我们的计算将完全不正确且未定义。所以,请记住这一点。
ABI
ABI 代表应用程序二进制接口。在使用以太坊时,这是比较难理解的事情之一,但我们会尽力解释它。
在新生教程中,在教程中你会进一步遇到,你会大量使用ABI
。
当 Solidity 代码被编译时,它被编译成本质上是二进制的字节码。它不包含合约中存在的函数名称、它们包含的参数以及它们返回的值的记录。
但是,如果您想从 Web 应用程序调用 Solidity 函数,则需要一种在合约中调用正确字节码的方法。为此,您需要一种将人类可读的函数名称和参数转换为字节码并返回的方法。
ABI 可以帮助我们实现这一目标。当你编译你的 Solidity 代码时,编译器会自动生成一个 ABI。它包含有关合约中存在的功能的规则和元数据,有助于进行正确的数据来回转换。
所以,当你想调用一个合约时,你需要它的地址(当然),但你也需要提供它的 ABI。像这样的库ethers.js
使用 ABI 将人类可读的函数编码和解码为字节码,然后在与以太坊节点通信和调用智能合约中的函数时返回。
ERC20 审批流程(ERC20 Approval Flow)
过去,我们了解了payable
允许智能合约在调用函数时接受 ETH 付款的函数。如果您想以 ETH 向用户收费以换取某些东西(例如 NFT 销售),这非常有用。
但是,如果你想使用 ETH 以外的东西进行支付怎么办?如果您想使用自己部署的加密货币进行支付怎么办?
这里的事情有点棘手。
由于 ETH 是以太坊的原生货币,而且 ERC20 标准是在以太坊发明之后很久才引入的,所以它们的行为方式并不完全相同。具体来说,接受 ERC20 代币支付并不像在 Solidity 中创建一个payable
函数那么简单。
该payable
关键字仅适用于 ETH 支付。如果您想使用自己的 ERC20 加密货币,那么执行此操作的流程会稍微复杂一些。
首先,让我们稍微考虑一下。
好的,所以你不能像使用 ETH 一样发送 ERC20 代币和函数调用
也许智能合约可以以某种方式从函数调用者的帐户中提取代币?
但这意味着我可以编写一个智能合约,如果有人用我的合约进行交易,它会窃取每个人的代币
因此,我们需要一种更安全的方法来从某人的帐户中提取代币,这就是
Approve and Transfer
流量的来源。
该ERC20
标准带有津贴的概念。
让我们试着借助一个例子来思考这个问题。
- Alice 想卖掉她的 NFT
- Alice 想用她自己的加密货币 AliceCoin 接受她的 NFT 付款
- Alice 的 NFT 花费 10 AliceCoin
- Bob 拥有 AliceCoin
- Bob 想购买 Alice 的 NFT
- Bob 需要一种方法来调用 Alice 的 NFT 智能合约上的函数,该函数将收取 10 Alicecoin 的付款,并将他的 NFT 发送给他
- 由于智能合约不能直接接受 Alicecoin 作为支付,Alice 在她的 NFT 合约中编码了
ERC20 Approval and Transfer
流程
Alicecoin
是 ERC20 代币。ERC20 内置了一些与 Allowance 概念相关的功能。
approve(address spender, uint256 amount)
这允许用户在approve
不同的地址代表他们花费最多amount
代币。即此功能提供了spender
最多的津贴amount
transferFrom(address from, address to, uint256 amount)
允许用户将amount
令牌从转移from
到to
。
如果调用函数的用户与from
地址相同,则从用户余额中删除代币。
如果用户是from
地址以外的其他人,则该from
地址必须在过去给予用户使用该approve
功能amount
使用代币的许可。
现在继续这个例子:
- Bob 允许 Alice 的 NFT 合约
Alicecoin
使用该approve
功能最多花费 10 - Bob 调用该函数在 Alice 的 NFT 合约上购买她的 NFT
- 购买函数内部调用
transferFrom
并Alicecoin
从 Bob 的账户中将 10Alicecoin
转移到 Alice 的账户中 - 由于之前 Bob 允许合约使用最多 10 个
Alicecoin
,因此允许此操作 - 因此,Alice 收到了她的 10 个
Alicecoin
,Bob 收到了他的 NFT
好的,那么这对我们意味着什么?
好吧,请注意 Bob 必须如何批准合同,因此合同可以从 Bob 的帐户中提取 Bob 的代币。
因此,如果在 ETH 中接受付款,Bob 基本上必须进行两次交易来复制一次交易中可以完成的行为。
交易 1 - 为合约提供津贴 交易 2 - 调用合约函数,该函数在内部使用津贴将 Bob 的代币转移到不同的地址
因此,如果您正在构建一个 dApp,您需要用户使用 ERC20 代币支付您的智能合约,您还需要让他们同时进行这两项交易。简单地调用你的合约函数,而不首先让你的用户为你的合约提供津贴,将导致函数调用失败。
在大二课程的最后一级构建 DeFi-Exchange 时,我们将遇到此流程的一个用例。由于交易所涉及能够将一种代币转换为另一种代币,因此您需要在交易所智能合约上调用一个函数,该函数接收一个代币并为您提供另一个代币。
要使用您的代币进行交换,交换合约需要获得批准才能从您的账户中提取代币。
因此,如果您想知道为什么在交易所进行交换可以使用两笔交易而不是一笔交易,请记住这一流程。
练习题
🤔 什么是提供者(Provider)?
A: 以太坊节点连接,可帮助您从状态中读取数据
B: 以太坊节点连接,帮助您写入数据状态
C: 可读写的以太坊节点连接
🤔 什么是签名者(Signer)?
A: 以太坊节点连接,可帮助您从状态中读取数据
B: 以太坊节点连接,帮助您写入数据状态
C: 可读写的以太坊节点连接
🤔 我们如何在 Bignumber 中进行乘法运算?
A: 使用 .mul()
B: 使用 *
C: 使用 x
🤔 ABI 包含什么?
A: 它是一个任意数组,它可以包含任何东西
B: 包含有关合约中存在的功能的规则和元数据
C: 仅包含合约中关于函数的规则
D: 仅包含有关合约中存在的功能的元数据
🤔 如果 Alice 想要一份合约从她那里拿走一些 ERC20 代币,她会怎么做?
A: 合约上的调用
transferFrom
函数B: ERC-20 合约上的调用
approve
函数C: ERC-20 合约上的调用
pay
函数D: ERC-20 合约上调用
approve
函数,然后在合约上调用一些内部使用的函数 transferFrom
参考答案:
- A
- C
- A
- B
- D