🌞Moon Will Know
🦊

Web3相关概念以及钱包交易流程

NetWork 网络

包含以下信息的一个JSON
{ "chainId": 1, // 链ID "ensAddress": "0x314159265dd8dbb310642f98f50c066173c1259b", // ENS 地址 "name": "homestead" // network 名称 }

Provider 提供者

提供者是一个连接以太坊网络的抽象,用与查询以太坊网络状态或者发送更改状态的交易。
连接BSC:
const provider = new ethers.providers.JsonRpcProvider('https://bsc-dataseed1.defibit.io/')

Singer 签名器

Wallet 钱包

继承Singer的一个类,主要api:
// 从私钥恢复钱包 const wallte = new Wallet('privateKey'); // 创建一个随机钱包 const wallte = Wallet.createRandom(); // 通过助记词恢复钱包 const wallte = Wallet.fromMnemonic('mnemonic');
钱包实例主要api:
// 连接一个提供者 并返回一个新的实例 const account = wallet.connect(provider); // 私钥 wallet.privateKey // 助记词 wallet.mnemonic // 地址 wallet.address // 以下操作需要 connect 一个 provider // 获取钱包(主币)余额 await wallet.getBalance() // 获取账号交易数量 await wallet.getTransactionCount() // 获取测算Gas await wallet.estimateGas(transation) // 发送交易到网络 await wallet.sendTransaction(transaction)

Contarct 智能合约

合约是在以太坊区块链上的可执行程序的抽象。合约具有代码 (称为字节代码) 以及分配的长期存储 (storage)。每个已部署的合约都有一个地址, 用它连接到合约, 可以向其发送消息来调用合约方法。
合约可以发出 事件, 它可以被应用程序监听(订阅), 当合约执行了特定操作时, 应用程序将收到通知。事件是无法在合约内读取的。
在合约上可以调用两种类型的方法:
视图方法 : 不能添加、移除或更改存储中的任何数据,也不能记录任何事件,并且只能调用其他合约上**视图方法**。 这些方法是免费的(不需要以太)调用。 结果也可以返回给调用者。
非视图方法: 需要支付费用(用Ether),但可以执行任何所需的状态更改操作,记录事件,发送ether并在其他合约上调用非视图方法。 这些方法**不能**将其结果返回给调用者。 这些方法必须由交易触发,由外部拥有的账户(EOA)直接或间接发送(如从另一个合约调用),并且只有在交易被打包(挖矿)后才会产生效果。 因此,这些操作所需的持续时间可能变化很大,并且取决于交易Gas价格、网络拥塞和矿工优先选择方法。
合约 API 提供了简单的方法来连接到一个合约并调用它的方法,它作为 JavaScript 对象上的函数,处理所有的二进制协议转换,内部名称修改和主题构造。 这使得合约对象可以像任何标准的JavaScript对象一样使用,而不必担心以太坊虚拟机或区块链的低级细节。
合约Contract对象是一个元类,它是一个在运行时定义类的类。 可以提供合约定义(称为应用程序二进制接口或ABI)以及可用的方法和事件可以动态添加到对象中。

ABI 应用二进制接口 application binary interface

对合约中的功能和事件的接口进行描述

连接合约

const contract = new ethers.Contract( contarctAddress, abi, provider );

Event Emitter 事件触发器

// 注册合约事件回调 contract.on('eventName',()=>{ .... }) // 注册一次性合约事件回调 contract.once('eventName',()=>{ .... }) // 触发合约事件 contract.emit('eventName',()=>{ .... })

查询对应token信息 余额

// 通过私钥连接钱包 const wallet = new ethers.Wallet('0x9b06f68b238c23c125481a3f61076e9e41812dba92013bc3c531b7950e77605d'); // 钱包地址 const address = wallet.address; // 连接主网 const provider = new ethers.providers.JsonRpcProvider('https://data-seed-prebsc-1-s3.binance.org:8545'); wallet.connect(provider) // 币种合约地址 const contarctAddress = '0x7ef95a0FEE0Dd31b22626fA2e10Ee6A223F8a684'; // USDT // 币种合约abi 可通过bsc查询 const abi = [{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[],"name":"_decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}] // 连接合约 const contract = new ethers.Contract( contarctAddress, abi, provider ); // 查询余额 contract.balanceOf(address).then((res:any)=>{ console.log(res) }) /** 合约一般包含以下方法 name:返回 token 名称 symbol:返回 token 的符号,比如EOS totalSupply:返回 token 的总供应量 balanceOf:返回账户的金额 transfer:对 token 进行交易 **/

GAS 手续费

gasLimit * gasPrice ,gasLimit 的最小值为 21000,但用户可以设置,gasPrice 和当前区块相关,如果 gas 费设置过低,交易有可能失败,手续费不会被退还。如果 gas 费设置过高,没有使用的 gas 会被返还。

Transaction 交易

通过wallet.sendTransaction() 发起交易。
交易请求
{ // Required unless deploying a contract (in which case omit) to: addressOrName, // the target address or ENS name // These are optional/meaningless for call and estimateGas nonce: 0, // the transaction nonce gasLimit: 0, // the maximum gas this transaction may spend gasPrice: 0, // the price (in wei) per unit of gas // These are always optional (but for call, data is usually specified) data: "0x", // extra data for the transaction, or input for call value: 0, // the amount (in wei) this transaction is sending chainId: 3 // the network ID; usually added by a signer }
交易回复
{ // Only available for mined transactions blockHash: "0x7f20ef60e9f91896b7ebb0962a18b8defb5e9074e62e1b6cde992648fe78794b", blockNumber: 3346463, timestamp: 1489440489, // Exactly one of these will be present (send vs. deploy contract) // They will always be a properly formatted checksum address creates: null, to: "0xc149Be1bcDFa69a94384b46A1F91350E5f81c1AB", // The transaction hash hash: "0xf517872f3c466c2e1520e35ad943d833fdca5a6739cfea9e686c4c1b3ab1022e", // See above "Transaction Requests" for details data: "0x", from: "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", gasLimit: utils.bigNumberify("90000"), gasPrice: utils.bigNumberify("21488430592"), nonce: 0, value: utils.parseEther(1.0017071732629267), // The chain ID; 0 indicates replay-attack vulnerable // (eg. 1 = Homestead mainnet, 3 = Ropsten testnet) chainId: 1, // The signature of the transaction (TestRPC may fail to include these) r: "0x5b13ef45ce3faf69d1f40f9d15b0070cc9e2c92f3df79ad46d5b3226d7f3d1e8", s: "0x535236e497c59e3fba93b78e124305c7c9b20db0f8531b015066725e4bb31de6", v: 37, // The raw transaction (TestRPC may be missing this) raw: "0xf87083154262850500cf6e0083015f9094c149be1bcdfa69a94384b46a1f913" + "50e5f81c1ab880de6c75de74c236c8025a05b13ef45ce3faf69d1f40f9d15b0" + "070cc9e2c92f3df79ad46d5b3226d7f3d1e8a0535236e497c59e3fba93b78e1" + "24305c7c9b20db0f8531b015066725e4bb31de6" }
交易收据
{ transactionHash: "0x7dec07531aae8178e9d0b0abbd317ac3bb6e8e0fd37c2733b4e0d382ba34c5d2", // The block this transaction was mined into blockHash: "0xca1d4d9c4ac0b903a64cf3ae3be55cc31f25f81bf29933dd23c13e51c3711840", blockNumber: 3346629, // The index into this block of the transaction transactionIndex: 1, // The address of the contract (if one was created) contractAddress: null, // Gas cumulativeGasUsed: utils.bigNumberify("42000"), gasUsed: utils.bigNumberify("21000"), // Logs (an Array of Logs) log: [ ], logsBloom: "0x00" ... [ 256 bytes of 0 ] ... "00", // Post-Byzantium hard-fork byzantium: false //////////// // Pre-byzantium blocks will have a state root: root: "0x8a27e1f7d3e92ae1a01db5cce3e4718e04954a34e9b17c1942011a5f3a942bf4", //////////// // Post-byzantium blocks will have a status (0 indicated failure during execution) // status: 1 }

通过钱包进行转帐

  1. 连接 network
const provider = new ethers.providers.JsonRpcProvider('https://bsc-dataseed1.defibit.io/');
  1. 创建 wallet
const wallet = new ethers.Wallet('privatekey');
  1. wallet 连接到 network ,获得 signer
const account = wallet.connect(provider);
  1. 查询 gasPrice
const gas_price = provider.getGasPrice();
  1. 构造交易参数
const tx = { from: send_account, to: to_address, value: ethers.utils.parseEther(send_token_amount), nonce: window.ethersProvider.getTransactionCount(send_account, "latest"), gasLimit: ethers.utils.hexlify(gas_limit), // 100000 gasPrice: gas_price, }
  1. 使用 signer 进行转账
account.sendTransaction(tx).then((transaction) => { console.dir(transaction) alert("Send finished!") })

使用合约进行转账

  1. 连接 network
const provider = new ethers.providers.JsonRpcProvider('https://bsc-dataseed1.defibit.io/');
  1. 创建 wallet
const wallet = new ethers.Wallet('privatekey');
  1. wallet 连接到 network ,获得 signer
const account = wallet.connect(provider);
  1. 连接 contact
let contract = new ethers.Contract('contractAddress' , 'abi' , account);
  1. 转账
contract.transfer(to_address, ethers.utils.parseEther(send_token_amount));