Ethereum基础
Ethereum概念
先跟着以太坊官方开发文档看一遍,差不多基本概念了解。
Solidity语法和JS基本一致。
Account
账户形式有两种,一种是合约账户,一种的普通账户。两者不同的点就是普通账户手里有私钥,合约账户没有私钥,所以无法随意转移token。
这就导致如果你的Token转进了合约账户且没有预留相关的方法转移这个token,则该Token数量将永远锁死。
GasPrice/GasLimit
GasPrice表示价格,用wei来表示,表示一个gas值多少钱。
GasLimit表示gas数量,表示我愿意最大用多少个gas来付费。超过了表示交易会滚,但是ETH = GasPrice * GasLimit * 1^-18
的钱依旧给矿工了。
一次以太坊交易所花的ETH = GasPrice * GasNumber * 1^-18
。GasNumber表示在一次交易或者合约调用时具体花费的gas数量。
下面是一个简单的转账交易,简单的转账交易一般gasLimit都是21000。而且gasNumber基本上是100%
当一次合约调用所设置的GasLimit大于实际花费的gas数量,则该交易失败,意味着你付费了但是没有得到任何的结果。这时候你需要提高的你的GasLimit来让合约执行。
GasPrice还决定了被执行的优先顺序,所有的交易会被放在sharepool中,然后按照GasPrice进行排序,高GasPrice会优先被执行,低GasPrice会被后执行。如果想要交易被快速执行,那么就提高GasPrice。
GasLimit存在的意义之一,保证了你写的合约代码没有死循环,因为每一个操作都会消耗一定的gas数,当你给的GasLimit超出了实际的消耗,则该交易会被回滚。也保护了以太坊不会遭受死循环攻击。
以太坊黄皮书中有合约每个操作具体花费的gas数量。
Unit Converter:https://etherscan.io/unitconverter?wei=1
GasTracker:https://etherscan.io/gastracker
GasNow:https://www.gasnow.org/
Web3合约调用
前端调用合约使用web3,可以理解以太坊区块链就是一个巨大的服务端,我们通过web3来访问服务端。
Infura
Infura可以理解为一个巨大的Nginx,通过他来访问以太坊(当然你也可以自己用geth同步所有区块,然后连接本地的RPC)。
MateMask钱包
钱包(开源):Chrome的Extension,基本上所有的DeFi应用(基于以太坊)的都会首选的钱包插件。
Truffle开发工具链
开发工具链(开源)。从开发、部署、测试都很完善,后面直接用这个工具部署到以太坊正式网络。
truffle:https://www.trufflesuite.com/
ganache:https://www.trufflesuite.com/ganache
部分玩家喜欢使用remix进行开发和部署,但个人觉得体验上来说并不是特别好(个人使用VSCode开发)。
- 启动本地开发链
1 | # 每次启动的时候助记词都不一样 |
- 添加
truffle-config.js
配置文件
1 | const HDWalletProvider = require('@truffle/hdwallet-provider'); |
- 编译/部署/测试
1 | # 编译 |
Write Contract
Decimals
10 ** 18
会出现溢出情况,应该改为uint256(10) ** 18
View/Pure
在solidity中,不改变链上状态的方法都要标记为view
或者pure
,否则调用该方法的时候会产生一笔交易,即使这个方法什么也没做。
emit
这种也会修改链上状态,所以不能在view
中使用。pure是严格不访问、不修改。view是严格不修改。
msg.sender
A => ContractA: msg.sender == A
ContractA => ContractB: 在ContractB中拿到的msg.sender == ContractA
A => ContractA => ContractB: 在ContractA中拿到的msg.sender == A,在ContractB中拿到的msg.sender == ContractA。
Float
solidity暂时不支持浮点型计算,所有的计算都是整型。
所以在计算的时候一般都是先乘然后再除,否则会出现精度丢失。
public/external
public修饰的方法内部和外部都可以直接通过函数名字调用。
external修饰的方法,只能是外部调用,如果内部想要调用需要通过this.functionName()
来调用。
在修饰view方法的时候没有区别,如果在内部通过
this.functionName()
来调用,则是转为外部调用(貌似会消耗更多gas?)
Truffle Migration
1 | /// 使用artifacts来创建一个引用 |
1
2
3 > /// 调用合约后面加上{ from: accounts[1] }表示使用指定的账户进行操作。而不默认使用accounts[0]
> let transferSuccess = await wbtc.transfer("0xabcdefghijklmnopqistuvwxyz", web3.utils.toBN(1e8), { from: accounts[1] });
>
bn.js
truffle使用了这个库作为uint类型的返回值或者参数传递。
bn.js: https://github.com/indutny/bn.js/
1 | exports.BN = (number) => { |
Truffle Test
1 | /// 测试基本结构 |
Truffle uses the Mocha testing framework and Chai for assertions to provide you with a solid framework from which to write your JavaScript tests.
详细使用:https://www.trufflesuite.com/docs/truffle/testing/writing-tests-in-javascript