去中心化借贷,Compound应用架构

Posted 33357

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了去中心化借贷,Compound应用架构相关的知识,希望对你有一定的参考价值。

原文发布在 https://github.com/33357/smartcontract-apps这是一个面向中文社区,分析市面上智能合约应用的架构与实现的仓库。欢迎关注开源知识项目!

Compound应用架构

服务架构

Compound 整个应用所依赖的服务分为以下几块:

  1. Web服务:为用户提供合约数据显示和操作的界面

  2. Ethereum钱包服务(Metamask):保管用户私钥,并负责签名和向区块链发送数据

  3. 智能合约服务:保存用户资产,提供可信的资产管理服务

  4. 价格预言机服务:提供资产价格

  5. 链上数据聚合服务(Subgraph):快速获得合约的状态

  6. 清算服务:清算超过禁戒线的账户资产

其中的数据流如图所示:

后端 区块链 客户端 私钥签名数据 清算操作 合约状态 可清算账户 链上数据 资产价格 用户操作 链上数据聚合 清算服务 智能合约 价格预言机 Web客户端 Ethereum钱包

合约架构

Compound合约主体分为以下几块:

  1. cToken:用户直接操作的合约,保存用户资产,提供业务接口

  2. interestRateModel:提供资产利率的计算模型

  3. comptroller:操作条件审查

  4. priceOracle:提供资产价格

其中的数据流如图所示:

利率模型 操作条件审查 用户操作 资产价格 interestRateModel cToken comptroller account priceOracle

Compound学习 简单部署

Compound学习(二) 简单部署

Compound 是 DeFi 的明星项目之一,定位于去中心化的借贷协议。可以称之为“去中心化的算法银行”。Compound 协议是为了开放金融系统而为开发者构建的开源协议,基于 Compound 协议可以开发一系列新的金融应用程序。

上一次学习了一下Compound的README.md文件,在文章的最后介绍了需要部署的合约,这次我们实际验证一下。

注:本次部署在以太坊Kovan测试网上进行。

一、编译合约

Fork后的Compound合约怎么编译部署呢?

1.1、使用Compound自带的脚本编译

我们先打开项目根目录下的package.json先看一下有什么脚本可运行。然后会发现scripts属性下有cmopile字段,也就是有编译脚本存在,于是我们直接运行下面的命令:

npm run compile

注:必须在学习(一)中提到的先运行npm install安装依赖库。

结果有些尴尬,会提示shasum命令中的-p选项找不到,运行shasum -h的确找不到-p选项,那么我们就稍微修改一下,直接把./scritp/compile文件中shasum -p中的-p选项去掉试下看能否运行。

再次运行脚本又会提示编译器版本不对,于是我们运行如下命令:

solc-select install 0.5.16
solc-select use 0.5.16
solc-select versions

最终会得到如下输出:

0.7.6
0.6.12
0.5.16 (current, set by /Users/user/.solc-select/global-version)

可以看到,我们最终使用了0.5.16版本的编译器。

再次运行npm run compile,最终我们编译成功(忽略那些警告)。此时可以在项目根目录下看到一个.build目录,里面有个contracts.json,包含了所有编译好的合约的相关信息,不过要是打开看,会有些眼花。

1.2、使用truffle编译

上面编译过程有些复杂,并且结果到结果也不方便查看,这次我们尝试使用常用的truffle工具来编译,安装truffle的过程就直接跳过了。

1.2.1、初始化项目

运行truffle init,会提示你是否重写contracts目录,记得选N。如果不小心选错了选的Y也不打紧,因为有git,可以撤销所有改变的。

1.2.2、设置编译器版本

打开truffle-config.js,将compilers字段改写如下并保存:

compilers: {
    solc: {
      version: "0.5.16",    // Fetch exact version from solc-bin (default: truffle's version)
      // docker: true,        // Use "0.5.1" you've installed locally with docker (default: false)
      settings: {          // See the solidity docs for advice about optimization and evmVersion
       optimizer: {
         enabled: true,
         runs: 200
       },
      //  evmVersion: "byzantium"
      }
    }
  }

1.2.3、编译

运行truffle compile,编译成功,不必理会那些编译警告。编译完成后项目根目录下会多一个build目录,打开后里面是所有用到的合约的编译好的信息(需要用的是abi和bytecode)。

好了,至此,Compound合约我们已经使用两种方式编译完成了,可以正式部署了。

二、部署常用代币

在部署Compound合约之前,我们先部署一下常用的代币,比如WETH,USDT,DAI什么的。

推荐使用remix来部署相关代币,因为这些代币在etherscan上都通过了浏览器验证,并且属于单文件合约,直接复制代码过来编译部署就完成了。

记住这里是在Kovan测试网上部署,笔者已经部署好了几个:

  • WETH地址:0xd0A1E359811322d97991E03f863a0C30C2cF029C (这个不用自己部署,别人部署过的,直接使用即可)
  • USDT地址:0xee095890Fef04aD2b53C4AdE71cD1B74429990C6 (这里需要用户自己部署,用别人部署好的自己会没有币)
  • DAI地址:0xf98aA77eF693d8721A722140A6d93b530D1964FD (同上)
  • ZRX地址:0x696D67a2AB7296527AF05aC1eb5d57fAC0A5a664 (同上)

注意:上面的地址均通过了浏览器验证,有需求的同学也可以直接在Kovan浏览器上直接复制代码,不需要查看etherscan上相关代币源码了。

注意:给自己发一些USDT,DAI或者ZRX,以后测试要用的。

三、简单化部署Compound

为什么叫简单化部署呢,我们当前只部署一个最小可用的(例如预言机不使用PriceOracleProxy.sol),也不使用社区治理功能(代币投票和时间锁定),因为我们主要是学习Compound功能嘛。

在这里,因为合约部署基本上没有单合约了,所以我们推荐使用MyEtherWallet这个网站在线部署,相应的网址为:

https://www.myetherwallet.com/access-my-wallet

这里选择第三项,MEW CX , 然后钩选访问我的钱包,就会连接你的METMASK。具体用法不再多讲,有兴趣的读者(不会的读者)需要自己研究下它的使用方法。

使用MyEtherWallet部署的另一个好处就是可以直接使用truffle编译完成后得到的合约abi和bytecode。

PS:很偶然的时候MyEtherWallet也会有些小BUG(影响部署),这时就只有自己写脚本来部署了,推荐使用ethers.js这个框架来执行部署任务。这里假定当前所有部署均不会出现myEtherWallet自身的问题。

3.1、部署COMP

因为Comptroller.sol中会使用到COMP的地址,因此我们最先部署COMP:

部署后的COMP地址为:0x106685Ee0EF56c4bAD04Bd4CBbCd564C5595fD48

3.2、部署价格预言机

直接部署SimplePriceOracle, 部署后的地址为:0x446F4017DF4cE00959C162d69D6f904505BbaaaE

3.3、部署Comptroller

  1. 替换Comptroller.sol中的COMP代币地址,也就是getCompAddress函数的返回值,改为上面部署的COMP地址。
  2. 重新编译,运行truffle compile
  3. 部署Comptroller实现,即Comptroller合约,部署后的地址为:0x86dD25622bd3dEDB0F6f7428b6BA4952409dC832
  4. 部署Comptroller代理,即Unitroller合约,部署后的地址为:0xeF960E96a4D15f4a7c09cE4dB70019F9E27D7Ad8
  5. 在调用Unitroller合约的 _setPendingImplementation函数设置实现地址
  6. 调用Comptroller合约的_become函数接受Unitroller。

记住对外提供Comptroller合约地址时是提供的Unitroller合约地址。

因此这里部署完成后的Comptroller地址为:0xeF960E96a4D15f4a7c09cE4dB70019F9E27D7Ad8

3.4、部署InterestRateModel

注意:源码中InterestRateModel合约为一抽象合约,我们需要部署它的一个实现,即WhitePaperInterestRateModel 合约。

注意:它有构造器需要两个参数,分别为基准APR和利息增长率(这参数作用以后再弄清楚),他们都要除于1e18。那么这个值输入多少合适呢?我们在etherscan上找到一个类似合约,先采用它们的值,分别为0.02e18和0.15e18,参考的合约地址为:https://etherscan.io/address/0x7b80ed50fb4465bca5d5807aad695d285a3e4b4b#code

部署完成后InterestRateModel地址为:0x49164696923C6001905CE9f757bab226a024b5A3

3.5、部署CToken

3.5.1、部署CErc20Delegate

这里所有的CToken也是采用委托代理模式的,所以我们先部署一个实现合约:

CErc20Delegate地址:0xDa4318A489aad6661a77441Be908Bac56e2cFEc3

3.5.2、部署cUSDT

因为每种Token代表一个市场,所以我们先创建常用的USDT市场,也就是部署一个cUSDT代币,这里我们部署的实际合约为CErc20Delegator合约。

这里可以看一下它的构造器源码,参数较多,我们直接看注释:

/**
   * @notice Construct a new money market
   * @param underlying_ The address of the underlying asset
   * @param comptroller_ The address of the Comptroller
   * @param interestRateModel_ The address of the interest rate model
   * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
   * @param name_ ERC-20 name of this token
   * @param symbol_ ERC-20 symbol of this token
   * @param decimals_ ERC-20 decimal precision of this token
   * @param admin_ Address of the administrator of this token
   * @param implementation_ The address of the implementation the contract delegates to
   * @param becomeImplementationData The encoded args for becomeImplementation
   */

从下至下参数的含义分别为:

  • underlying_ 底层代币地址,这里我们就是USDT地址了,上面已经部署好了,见部署常用代币。
  • comptroller_ 就是部署的Unitroller地址
  • interestRateModel_ 就是部署的InterestRateModel地址
  • initialExchangeRateMantissa_ 初始交换率,也就是底层代币和cToken兑换比较,为了简化,我们1:1兑换好了,所以这里就设置1e18。
  • name_ 名称 Compound USDT Token
  • symbol_ 符号 cUSDT
  • decimals_ 精度 为了方便我们和原代币一样,18
  • admin_ 管理员地址,就用自己的账号地址吧,标准Compound这里应该是时间锁定合约地址
  • implementation_ 实现地址,就是上一步部署的CErc20Delegate地址
  • becomeImplementationData 额外的初始数据,这里其实没有用上,我们就使用空数据0x吧。

部署后的CErc20Delegator(cUSDT)地址:0x83f7A6B8D106f0440ab58744A98E65b43aD843F3

3.5.3、部署cDAI与cZRX

我们再部署一个cDAI用来代表DAI市场,方法和上面的cUSDT一样,直接部署CErc20Delegator合约即可。

只需要将名称和underlying_作修改,构造器参数完全一样

部署后的cDAI地址为:0x991b142B309F201435c40E2b183A8d1f3fa41f70

接着我们再部署一个cZRX,地址为: 0xDcAB01C24be4e0FB6f12590cE737a5229E6321E2

四、浏览器验证

我们基本合约已经部署完毕了,为了方便下一步设计和测试,我们对部分合约进行浏览器验证操作。

具体验证的过程就不再细述了,主要验证CToken合约和Unitroller合约。

部署多个CErc20Delegator时,只需要任意验证其中一个即可。

由于浏览器验证无法跨目录选择文件,因此没法直接验证Comptroller合约,但Unitroller合约可以验证。要想验证 Comptroller 合约,只有将COMP.sol复制一份放入项目根目录中,并且修改Comptroller.sol中的导入路径,重新编译后部署。此时,需要重新设置Unitroller中的实现地址并且新地址要接受才可以。有兴趣的读者可以自己尝试一下。但由于未知原因,笔者进行 Comptroller合约的验证尝试失败了,还望有成功过的读者告知一下。

这次的简单部署就到此结束了,下一次学习基本的设置和用户操作。

自己也是边学边写,欢迎读者留言指正错误或者提出改进建议。

以上是关于去中心化借贷,Compound应用架构的主要内容,如果未能解决你的问题,请参考以下文章

Compound学习 README.md

Compound学习 测试存入和取回资产

DeFi明星协议进军B端市场

Trister‘s Lend告诉你如何选对借贷平台

BLOCKCHAIN 区块链的去中心化P2P服务的JAVA代码的实现

用 Python 开发 DeFi 去中心化借贷应用(下)