DApp开发入门

近一两年随着DeFi的火热,DApp开发也受到越来越多的关注,单纯从概念来说,DApp还是比较容易理解的,也就是App + decentralization(去中心化)。而去中心化我个人认为主要体现在两个方面,一是账户体系,二是服务或数据

账户体系也就是我们的钱包账户。

服务或数据,则对应我们的智能合约以及链上数据,获取这些数据非常简单,不需要Token认证,也不需要session,cookie,一切都是可以公开访问的,甚至你可以直接在一些区块链浏览器直接操作合约。

本文仅介绍以太坊系列的DApp开发,其他链原理差不太多。

目标

  1. 了解一些基础的区块链概念和操作
  2. 熟悉与MetaMask钱包的交互
  3. 了解ERC20 Token、并与ERC20合约进行交互
  4. 在Mdex的某个矿池中抵押LP Token(流动性证明),赎回LP Token

环境与工具

  1. 需要安装MetaMask钱包并创建或导入账号
  2. ethers.js (与以太坊区块链及其生态系统进行交互的JavaScript库),也可以用web3.js
  3. create-react-app(demo相关)
  4. Heco区块链浏览器

钱包操作

MetaMask安装完成并运行后,可以在Chrome控制台打印MetaMask注入的window.ethereum对象

截屏2021-06-04 上午10.55.39.png

关于ethereum对象,我们只需要关心ethereum.request就足够了,MetaMask 使用ethereum.request(args)方法来包装 RPC API。这些 API 基于所有以太坊客户端公开的接口。 简单来说钱包交互的大部分操作都是由request()方法实现,通过传入不同的方法名来区分。

⚠️即使ethereum对象中提供了chainId,isMetaMask,selectAddress属性,我们也不能完全相信这些属性,他们是不稳定或不标准,不建议使用。我们可以通过上面说的request方法,拿到可靠的数据

钱包通过method方法名,进行对应的实现 以获取钱包地址为例

调用ethereum.request({ method: "eth_requestAccounts" }),钱包实现了该方法,那么就可以拿到钱包的地址了。

case "eth_requestAccounts":
    return ["0xFD513D86a57BAFeAf46ddcC1bDDf629409A03cCf"]

常见的钱包操作

  1. 连接钱包

    const accounts = await ethereum.request({ method: "eth_requestAccounts" });
    const account = accounts[0];
    
  2. 监听网络和账号切换事件

    //监听账户变化
    ethereum.on("accountsChanged", (accounts) => {
      setAccount(accounts[0]);
    });
    //监听网络变化
    ethereum.on("chainChanged", (chainId) => {
      setChainId(chainId);
    });
    
  3. 添加自定义代币(添加自己的平台币到钱包账户,是个非常方便的功能。基于EIP-747

    const Dog = {
      symbol: "Dog",
      decimals: 18,
      image: "https://hecoinfo.com/token/images/dogtoken_32.png",
      address: "0xb3863e02d6930762933f672ca134c1ccecd0d413",
    };
    
    ethereum.request({
      method: "wallet_watchAsset",
      params: {
        type: "ERC20", // Initially only supports ERC20, but eventually more!
        options: Dog,
      },
    });
    
  1. 添加自定义网络(像Mdex支持同时支持ETH、HECO、BSC,MetaMask只有ETH主网和测试网,可以直接通过此协议增加对应的网络到钱包,如果钱包支持的话,基于EIP-3085仅支持非内置网络),社区目前有个EIP-3326提案,可以直接在以太坊网络进行切换。

    const Dog = {
      symbol: "Dog",
      decimals: 18,
      image: "https://hecoinfo.com/token/images/dogtoken_32.png",
      address: "0xb3863e02d6930762933f672ca134c1ccecd0d413",
    };
    
    ethereum.request({
      method: "wallet_watchAsset",
      params: {
        type: "ERC20", // Initially only supports ERC20, but eventually more!
        options: Dog,
      },
    });
    

Provider

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

MetaMask注入的window.ethereum就是一个Provider,一个RPC节点也是一个Provider,通过Provider,我们有了访问区块链的能力。 在连接到钱包的情况下,通常使用钱包的Provider就可以了,ethers.providers.Web3Provider(ethereum)

如果只需要查询一些区块链数据,可以使用EtherscanProvider 和 InfuraProvider 连接公开的第三方节点服务提供商。JsonRpcProvider 和 IpcProvider 允许连接到我们控制或可以访问的以太坊节点。

获取当前账户余额

const balance = await provider.getBalance(account);

获取最新区块号

const blockNumber = await provider.getBlockNumber();

其他RPC操作,可以通过JSON-RPC查看。

ERC20 Token

ERC20 通证标准(ERC20 Token Standard)是通过以太坊创建通证时的一种规范。按照ERC20的规范可以编写一个智能合约,创建"可互换通证"。它并非强制要求,但遵循这个标准,所创建的通证可以与众多交易所,钱包等进行交互。目前的平台币基本都遵循ERC20标准。

contract ERC20 {
      function name() constant returns (string name)
      function symbol() constant returns (string symbol)
      function decimals() constant returns (uint8 decimals)
      function totalSupply() constant returns (uint totalSupply);
      function balanceOf(address _owner) constant returns (uint balance);
      function transfer(address _to, uint _value) returns (bool success);
      function transferFrom(address _from, address _to, uint _value) returns (bool success);
      function approve(address _spender, uint _value) returns (bool success);
      function allowance(address _owner, address _spender) constant returns (uint remaining);
      event Transfer(address indexed _from, address indexed _to, uint _value);
      event Approval(address indexed _owner, address indexed _spender, uint _value);
}

通过ethers.js可以连接ERC20的合约,合约编译后会生成ABI,合约部署后,会生成合约地址,开发者通过ABI和合约地址,对合约发送消息。

合约中的方法大致分为两种:视图方法(免费),非视图方法(消耗Gas),可以通过ABI查看方法类型。

截屏2021-06-08 上午10.10.11.png
  1. 初始化ERC20合约,如果是视图方法,只是进行数据的读取,传入Provider就可以,如果需要更改合约状态,需要用户签名,则需要传入Signer

    需要Token的合约地址和ERC20的合约ABI,可以通过浏览器查询到相关的信息,例如Dog

    new ethers Contract( addressOrName, abi,providerOrSigner)
    
  2. 查询合约的相关信息,这里以Heco的Dog为例,其他的Token都是一样的。

    const totalSupply = await contract.totalSupply();
    const balance = await contract.balanceOf(account);
    
  3. Transfer,转账的单位是Wei,可以通过etherjs提供的工具函数进行转换。

    const contract = new ethers.Contract(
          Dog.address,
          ERC20ABI,
          provider.getSigner()
        );
     const tx = await contract.transfer(
         "0xFD513D86a57BAFeAf46ddcC1bDDf629409A03cCf",
         parseEther("1.0")
      );
    

⚠️ERC20需要多加关注的是Approve()方法以及transfer()transferFrom()的区别,授权过的代币,被授权的那一方,可以通过调用transferFrom()方法,转走你授权数量内的代币,所以授权是一个很危险的操作,假设你授权了一个不良的合约,那你会面临授权的token被转走的风险,即使你没有泄露私钥助记词。

抵押和赎回

挖矿合约仅需要了解大概过程,挖矿合约并非标准,涉及到具体业务 这里选择Mdex DEP-HUSD矿池进行操作,也就是抵押DEP-HUSD LP Token 获取Mdex 。 此处已经提前添加了LP Token以及进行了Approve操作。

操作成功与否可以通过Mdex页面进行查看或在浏览器进行查询

  1. 从HecoInfo上获取到Mdex Pool的ABI,通过ABI连接Mdex Pool的合约

    const pool = new ethers.Contract(
          POOL_ADDRESS,
          POOLABI,
          provider.getSigner()
        );
    
  2. 抵押全部的LP

      const pid = await pool.LpOfPid(LP_ADDRESS);
    
      const lpToken = new ethers.Contract(LP_ADDRESS, ERC20ABI, provider.getSigner());
      //抵押
      const lpBanlance = await lpToken.balanceOf(account);
      const tx = await pool.deposit(pid, lpBanlance);
    
  3. 赎回全部的LP

    const pid = await pool.LpOfPid(LP_ADDRESS);
    const userInfo = await pool.userInfo(pid, account);
    const tx = await pool.withdraw(pid, userInfo[0]);
    

文档与三方库

便利三方库:web3-react use-wallet

文档:doc.metamask.io ethers

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容