JavaScript 开发人员的 Solidity 基础知识(第二部分)
我的第一篇关于JavaScript 开发人员 Solidity 基础知识的文章获得了如此多的关注,所以我决定写第二篇!
我目前正在学习一本入门级的智能合约开发书籍,现在正在进行主要项目,即一个 DApp 筹款项目。
这本书是用 Truffle、web3.js 和 JavaScript 编写的,为了增加一些趣味性,我用Hardhat、Ethers.js和 TypeScript 替换了这些工具。
以下是我最近的一些发现,这些发现让我有点意外,所以我认为它们可能对新手来说很有趣!
Solidity 事件是为前端设计的。
Solidity 具有事件结构/类型。它允许你为智能合约定义特定的事件,以便在发生你认为有趣的事情时触发。
event MyEvent( uint256 value1, uint256 value2);
function f() public {
emit MyEvent(123, 456);
}
对谁有用?对你的前端代码来说!
如果我理解正确的话,事件数据会存储在区块链中,但智能合约无法访问这些数据。
事件数据供区块链外部的监听者使用。
您的前端可以为这些事件添加事件监听器,然后,当它开始一个事务时,这些事件将被发出,您就可以在前端执行操作。
smartContract.on("MyEvent", (valueA, valueB) => {
console.log(valueA, valueB);
})
await smartContract.f();
Ethers.js 使用BigNumber代替BigInt
Solidity 通常需要处理非常大的整数,这超出了NumberJavaScript 类型所能处理的范围。因此,Ethers.js 创建了名为 `int` 的类型BigNumber来解决这个问题。
如今,现代 JavaScript 引擎都有一种BigInt类型可以轻松处理此类值,但情况并非一直如此,Ethers.js 希望保持向后兼容性。
我不知道他们为什么不用BigIntpolyfill,但至少他们提供了一种方法。不过,计算toBigInt()必须用方法!BigNumber
const value1 = ethers.utils.parseEther("1")
const value2 = ethers.utils.parseEther("2")
const result = value1.add(value2)
console.log(result.toBigInt())
总之,千万别搞混BigNumber了BigInt,否则你会倒霉的!
msg从 Ether.js设置对象
你的 Solidity 智能合约中有一些全局变量会在函数调用之前自动生成。
其中一个名为msg,它包含未通过函数参数显式传递的数据,例如msg.sender调用函数的地址或msg.value通过函数调用发送的以太币数量。
function f(uint256 arg1, uint256 arg2) public payable {
// These are obviously arguments
uint256 a = arg1 + arg2;
// But where do these come from?
address x = msg.sender;
uint256 y = msg.value;
}
由于该数据不是函数参数,如何从 Ethers.js 端将其传递给智能合约?
在所有常规参数之后,覆盖对象会作为最后一个参数传递给此类(可付费)函数。其他值(例如)msg.sender则在智能合约端隐式设置。
const overrides = {value: 123}
await smartContract.payableFunction(arg1, arg2, overrides)
在 Ethers.js 中,多个返回值将合并为一个数组。
Solidity 允许从一个函数返回多个值。
function f() public returns(uint256 a, uint256 b) {
return (123, 456);
}
我看到一些示例,似乎是针对 web3.js 的,它们会在 JavaScript 端使用对象作为返回值。
const {a, b} = await smartContract.f();
这种方法对我不起作用;我使用数组根据返回值的位置提取它们。
const [a, b] = await smartContract.f();
使用 Waffle 和 Chai 进行测试
我正在读的那本书使用了底层断言和一些 try-catch 结构来测试智能合约的特定行为。我猜那时候还没有 Waffle 这种工具吧。
要测试事件,可以使用异步调用expect。
it("emits", async () => {
await expect(smartContract.f()).to.emit("EventType")
})
您可以使用异步调用来expect测试reverted您的合约是否能正确回滚。
it("emits", async () => {
await expect(smartContract.f()).to.be.revertedWith("Error Message")
})
概括
Web3是个很有意思的话题,而Solidity也确实和我预想的完全不同。它像JavaScript一样简单,但魔鬼藏在细节里。
希望我能帮您解惑。
文章来源:https://dev.to/fllstck/solidity-basics-for-javascript-devs-part-2-430e