当前位置:   article > 正文

自学Vue开发Dapp去中心化钱包(四)_ether.js+vue项目

ether.js+vue项目

目录

前言

一、ethers.js术语

二、ethers.js使用

1.Provider

方法示例

监听

2.Wallet

方法示例

3.Contracts

用法示例

合约abi

监听

4.utils

 部分示例

 三、从0到1

需求功能点

开发功能

1.连接MetaMask

2.监听账户变化

3.provider和合约对象

 4.唤起MetaMask签名

5.链上转账、余额查询

总结


前言

        本文记录Vue框架前端使用ethers.js开发web3钱包相关功能。主要是前端调用ethers.js的相关用法。


一、ethers.js术语

1.Provider 是一个连接以太坊网络的抽象,用与查询以太坊网络状态或者发送更改状态的交易。

2.Wallet  类管理着一个公私钥对用于在以太坊网络上密码签名交易以及所有权证明。

3.Signer 是一个抽象类,当需要签名器Signer 时就可以扩展实现它。主要用于对交易消息最新签名,发到后台需要验签。

4.Contracts 合约是在以太坊区块链上的可执行程序的抽象。合约具有代码 (称为字节代码) 以及分配的长期存储 (storage)。每个已部署的合约都有一个地址, 用它连接到合约, 可以向其发送消息来调用合约方法。

5.Utils 工具包提供了大量的通用实用函数去编写 dapps、处理用户输入和格式化数据等功能。

ProviderA Provider (in ethers) is a class which provides an abstraction for a connection to the Ethereum Network. It provides read-only access to the Blockchain and its status.
SignerA Signer is a class which (usually) in some way directly or indirectly has access to a private key, which can sign messages and transactions to authorize the network to charge your account ether to perform operations.
ContractA Contract is an abstraction which represents a connection to a specific contract on the Ethereum Network, so that applications can use it like a normal JavaScript object.

二、ethers.js使用

1.Provider

Provider主要提供读属性,取得provider后可以查询账户信息及太坊状态。

方法示例

  1. 1.连接以太坊:MetaMask
  2. //window.ethereum是一个以太坊对象,MetaMask会向网页注入一个全局的API变量window.ethereum
  3. //登录连接到MetaMask后可以获取provider
  4. const provider = new ethers.providers.Web3Provider(window.ethereum)
  5. 2.获取signer
  6. const signer = provider.getSigner();
  7. //调取MetaMask小狐狸钱包签名
  8. let msg = address+amount...;//约定好签名规则即可
  9. const signature = await signer.signMessage(msg);
  10. 3.获取账户余额
  11. provider.getBalance(address).then((balance) => {
  12. // 余额是 BigNumber (in wei); 格式化为 ether 字符串
  13. let etherString = ethers.utils.formatEther(balance);
  14. console.log("Balance: " + etherString);
  15. });
  16. 或者
  17. const balance = await provider.getBalance(address);
  18. // 余额是 BigNumber (in wei); 格式化为 ether 字符串,使用工具包格式化成字符串
  19. let balanceStr = ethers.utils.formatUnits(balance, 18);
  20. 4.获取交易数
  21. let address = "0x02F024e0882B310c6734703AB9066EdD3a10C6e0";
  22. provider.getTransactionCount(address).then((transactionCount) => {
  23. console.log("发送交易总数: " + transactionCount);
  24. });
  25. 5.获取当前状态
  26. //当前的区块号
  27. provider.getBlockNumber().then((blockNumber) => {
  28. console.log("Current block number: " + blockNumber);
  29. });
  30. //当前的gas费
  31. provider.getGasPrice().then((gasPrice) => {
  32. // gasPrice is a BigNumber; convert it to a decimal string
  33. gasPriceString = gasPrice.toString();
  34. console.log("Current gas price: " + gasPriceString);
  35. });

监听

  1. 1.监听事件,监听小狐狸钱包余额变化
  2. let address = '';
  3. this.provider.on(address, (bal) => {});
  4. 2.监听区块
  5. provider.on("block", (blockNumber) => {
  6. // Emitted on every block change
  7. console.log("blockNumber: " + blockNumber);
  8. })

2.Wallet

Wallet实现了Signer,所以交易时使用Wallet就行。

本人目前没有使用到wallet对象,目前使用的是后端开发的合约方式

方法示例

  1. 1.创建钱包-随机钱包
  2. //Wallet . createRandom ( [ options ] ) => Wallet
  3. //创建一个随机钱包实例。 确保钱包(私钥)存放在安全的位置,如果丢失了就没有办法找回钱包。
  4. let randomWallet = ethers.Wallet.createRandom();
  5. 2.创建钱包-加载JSON钱包文件
  6. let data = {
  7. id: "fb1280c0-d646-4e40-9550-7026b1be504a",
  8. address: "88a5c2d9919e46f883eb62f7b8dd9d0cc45bc290",
  9. Crypto: {
  10. kdfparams: {
  11. dklen: 32,
  12. p: 1,
  13. salt: "bbfa53547e3e3bfcc9786a2cbef8504a5031d82734ecef02153e29daeed658fd",
  14. r: 8,
  15. n: 262144
  16. },
  17. kdf: "scrypt",
  18. ciphertext: "10adcc8bcaf49474c6710460e0dc974331f71ee4c7baa7314b4a23d25fd6c406",
  19. mac: "1cf53b5ae8d75f8c037b453e7c3c61b010225d916768a6b145adf5cf9cb3a703",
  20. cipher: "aes-128-ctr",
  21. cipherparams: {
  22. iv: "1dcdf13e49cea706994ed38804f6d171"
  23. }
  24. },
  25. "version" : 3
  26. };
  27. let json = JSON.stringify(data);
  28. let password = "foo";
  29. ethers.Wallet.fromEncryptedJson(json, password).then(function(wallet) {
  30. console.log("Address: " + wallet.address);
  31. // "Address: 0x88a5C2d9919e46F883EB62F7b8Dd9d0CC45bc290"
  32. });
  33. 3.创建钱包-加载助记词
  34. let mnemonic = "radar blur cabbage chef fix engine embark joy scheme fiction master release";
  35. let mnemonicWallet = ethers.Wallet.fromMnemonic(mnemonic);
  36. // Load the second account from a mnemonic
  37. let path = "m/44'/60'/1'/0/0";
  38. let secondMnemonicWallet = ethers.Wallet.fromMnemonic(mnemonic, path);
  39. // Load using a non-english locale wordlist (the path "null" will use the default)
  40. let secondMnemonicWallet = ethers.Wallet.fromMnemonic(mnemonic, null, ethers.wordlists.ko);
  41. 4.从已有实例创建新的Wallet实例
  42. //privateKey是小狐狸钱包账户的私钥,可以在钱包处看到
  43. let privateKey = "0x0123456789012345678901234567890123456789012345678901234567890123";
  44. let wallet = new ethers.Wallet(privateKey);
  45. // Connect a wallet to mainnet
  46. let provider = ethers.getDefaultProvider();
  47. let walletWithProvider = new ethers.Wallet(privateKey, provider);
  48. 5.余额和交易数
  49. let balancePromise = wallet.getBalance();
  50. balancePromise.then((balance) => {
  51. console.log(balance);
  52. });
  53. let transactionCountPromise = wallet.getTransactionCount();
  54. transactionCountPromise.then((transactionCount) => {
  55. console.log(transactionCount);
  56. });

3.Contracts

合约Contract对象是一个元类,它是一个在运行时定义类的类。 可以提供合约定义(称为应用程序二进制接口或ABI)以及可用的方法和事件可以动态添加到对象中。

创建和部署合约这块我前端没涉及,以后明白了再补偿。

我这里使用到连接已有合约并执行转账等操作。

用法示例

  1. 1.连接已有合约
  2. // The Contract interface
  3. let abi = [
  4. "event ValueChanged(address indexed author, string oldValue, string newValue)",
  5. "constructor(string value)",
  6. "function getValue() view returns (string value)",
  7. "function setValue(string value)"
  8. ];
  9. //const abi= require("../config/constants/contract-abi.json");//将abi单独存放到json文件中
  10. // Connect to the network,查看provider获取连接provider对象
  11. let provider = new ethers.providers.Web3Provider(window.ethereum)
  12. // 地址来自上面部署的合约
  13. let contractAddress = "0x2bD9aAa2953F988153c8629926D22A6a5F69b14E";
  14. // 使用Provider 连接合约,将只有对合约的可读权限
  15. let daiContract = new ethers.Contract(contractAddress, abi, provider);
  16. 2.合约代币转账
  17. //合约使用signer签名,查询provider的用法
  18. let signer = provider.getSigner();
  19. const daiWithSigner = daiContract.connect(signer);
  20. const dai = ethers.utils.parseUnits(amount.toString(), 18);
  21. //执行转账动作,这里的transfer是部署的合约abi定义的转账方法
  22. daiWithSigner.transfer(to, dai).then((resp) => {})
  23. .catch((err) => {});
  24. 3.代币余额查询
  25. const balance = await daiContract.balanceOf(address);
  26. let balanceStr = ethers.utils.formatUnits(balance, 18);

合约abi

  1. //contract-abi.json
  2. [
  3. {
  4. "inputs": [
  5. {
  6. "internalType": "address",
  7. "name": "to",
  8. "type": "address"
  9. },
  10. {
  11. "internalType": "uint256",
  12. "name": "amount",
  13. "type": "uint256"
  14. }
  15. ],
  16. "name": "transfer",
  17. "outputs": [
  18. {
  19. "internalType": "bool",
  20. "name": "",
  21. "type": "bool"
  22. }
  23. ],
  24. "stateMutability": "nonpayable",
  25. "type": "function"
  26. },
  27. {
  28. "inputs": [
  29. {
  30. "internalType": "address",
  31. "name": "account",
  32. "type": "address"
  33. }
  34. ],
  35. "name": "balanceOf",
  36. "outputs": [
  37. {
  38. "internalType": "uint256",
  39. "name": "",
  40. "type": "uint256"
  41. }
  42. ],
  43. "stateMutability": "view",
  44. "type": "function"
  45. },
  46. {
  47. "anonymous": false,
  48. "inputs": [
  49. {
  50. "indexed": false,
  51. "internalType": "address",
  52. "name": "from",
  53. "type": "address"
  54. },
  55. {
  56. "indexed": false,
  57. "internalType": "uint256",
  58. "name": "fromBalance",
  59. "type": "uint256"
  60. },
  61. {
  62. "indexed": false,
  63. "internalType": "address",
  64. "name": "to",
  65. "type": "address"
  66. },
  67. {
  68. "indexed": false,
  69. "internalType": "uint256",
  70. "name": "toBalance",
  71. "type": "uint256"
  72. },
  73. {
  74. "indexed": false,
  75. "internalType": "uint256",
  76. "name": "amount",
  77. "type": "uint256"
  78. }
  79. ],
  80. "name": "TransferNew",
  81. "type": "event"
  82. }
  83. ]

监听

  1. daiContract.on("TransferNew", (from, fromBalance,to,toBalance, amount, event) => {
  2. // let balanceStr = ethers.utils.formatUnits(fromBalance, 18);
  3. // console.log("fromBalance:::"+fromBalance);
  4. // this.$store.dispatch('SET_BALANCE', balanceStr);
  5. });

4.utils

 部分示例

  1. import * as ethers from 'ethers';
  2. 1.BigNumber类型转成可读的字符串
  3. let balanceStr = ethers.utils.formatUnits(balance, 18);
  4. 2.字符串转成BigNumber
  5. let amount = 1000;
  6. let amountBig = ethers.utils.parseUnits(amount.toString(), 18);
  7. 3.校验是否为以太坊账户地址
  8. //返回true或者false
  9. let isAddress = ethers.utils.isAddress(address);
  10. 4.随机数
  11. let randomNumber = utils.bigNumberify(utils.randomBytes(32));
  12. // BigNumber { _hex: 0x617542634156966e0bbb6c673bf88015f542c96eb115186fd93881518f05f7ff }

 三、从0到1

需求功能点

1.连接MetaMask小狐狸钱包;

2.监听账户变化,即时更新页面信息;

2.链上转账(代币合约转账),唤起小狐狸钱包签名对转账消息签名;

3.代币余额查询,账户切换时即时刷新;

开发功能

1.连接MetaMask

  1. //我们前面provider提到,MetaMask在安装后会发布一个全局的对象window.ethereum
  2. //参照小狐狸钱包的官方API:https://docs.metamask.io/guide/getting-started.html#basic-considerations
  3. //通过eth_requestAccounts获取连接的账户,未连接时弹出小狐狸钱包的连接页面
  4. const addressArray = await web3Provider.request({
  5. method: "eth_requestAccounts",
  6. });
  7. //通过eth_accounts获取当前连接的账户
  8. const addressArray = await web3Provider.request({
  9. method: "eth_accounts",
  10. });

 具体代码

  1. //写在了store的action里
  2. //连接小狐狸钱包
  3. export const connectWallet= async ({ commit }) => {
  4. let web3Provider;
  5. if (window.ethereum) {
  6. web3Provider = window.ethereum;
  7. try {
  8. //通过
  9. const addressArray = await web3Provider.request({
  10. method: "eth_requestAccounts",
  11. });
  12. let address = addressArray[0];
  13. const obj = {
  14. status: "
    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/453467
    推荐阅读
    相关标签