去中心化借贷,Compound应用架构
Posted 33357
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了去中心化借贷,Compound应用架构相关的知识,希望对你有一定的参考价值。
原文发布在 https://github.com/33357/smartcontract-apps这是一个面向中文社区,分析市面上智能合约应用的架构与实现的仓库。欢迎关注开源知识项目!
Compound应用架构
服务架构
Compound 整个应用所依赖的服务分为以下几块:
-
Web服务:为用户提供合约数据显示和操作的界面
-
Ethereum钱包服务(Metamask):保管用户私钥,并负责签名和向区块链发送数据
-
智能合约服务:保存用户资产,提供可信的资产管理服务
-
价格预言机服务:提供资产价格
-
链上数据聚合服务(Subgraph):快速获得合约的状态
-
清算服务:清算超过禁戒线的账户资产
其中的数据流如图所示:
合约架构
Compound合约主体分为以下几块:
-
cToken:用户直接操作的合约,保存用户资产,提供业务接口
-
interestRateModel:提供资产利率的计算模型
-
comptroller:操作条件审查
-
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
- 替换Comptroller.sol中的COMP代币地址,也就是
getCompAddress
函数的返回值,改为上面部署的COMP地址。 - 重新编译,运行
truffle compile
。 - 部署Comptroller实现,即Comptroller合约,部署后的地址为:0x86dD25622bd3dEDB0F6f7428b6BA4952409dC832
- 部署Comptroller代理,即Unitroller合约,部署后的地址为:0xeF960E96a4D15f4a7c09cE4dB70019F9E27D7Ad8
- 在调用Unitroller合约的 _setPendingImplementation函数设置实现地址
- 调用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应用架构的主要内容,如果未能解决你的问题,请参考以下文章