1. Hi区块链首页
  2. 资讯
  3. 竞争币

科普 | Compound的cToken及相关核心函数

Compound的cToken是什么,它又是如何实现去中心化借贷的呢?

去中心化金融(DeFi)协议Compound支持的所有资产,都是通过cToken智能合约来封装集成的,用户通过铸造代币(cToken)向协议提供资产,然后你只要持有cToken,就可以赚取到利息,而当你选择赎回后,每个cToken都可兑换成相应的基础资产。

可以说,cToken是与Compound协议交互的主要方式。每个cToken合约都创造了自己的货币市场,而用户铸币、赎回、借款、偿还借款、清算借款或转让cToken时,他们将使用到cToken合约。

目前,Compound协议有两种类型的cToken:CErc20和CEther,其中CErc20封装的是ERC-20资产,而CEther则封装的是以太币。

4

(当前Compound协议支持的7种cToken及对应合约地址)

而在这篇文章中,我们将了解Compound协议的核心函数:

  1. Mint(铸币);
  2. Redeem(赎回);
  3. Redeem Underlying(赎回基础资产);
  4. Borrow(借款);
  5. Repay Borrow(偿还借款);
  6. Repay Borrow Behalf;
  7. Liquidate Borrow(清算借款);
  8. 故障信息
  9. Exchange Rate(兑换汇率);
  10. Get Cash(获取Cash);
  11. Total Borrow(借款总额);
  12. Borrow Balance(借款余额);
  13. Borrow Rate(借款利率);
  14. Total Supply(总供给量);
  15. Supply Balance(供应余额);
  16. Supply Balance Underlying(基础资产供应余额);
  17. Supply Rate(供应率);
  18. Total Reserves(总储备金);
  19. Reserve Factor(储备金率);

 

1、铸币(Mint)

 

铸币(Mint)函数负责将资产转移到货币市场,后者根据资产的当前供应率计算利息。铸造的代币数量,根据用户所提供的基础资产数量除以当前汇率得出。

铸币(Mint)相当于Compound 协议的供应来源。

CErc20


function mint(uint mintAmount) returns (uint)
  1. msg.sender : 提供资产并拥有铸造cToken的帐户;
  2. mintAmount : 以基础资产为单位进行铸币的金额;
  3. RETURN:返回0表示成功,其它则是错误代码;

在提供资产之前,用户必须首先批准cToken以访问其代币余额;

CEther


function mint() payable
  1. msg.value (payable):以太币待提供金额,单位为wei;
  2. msg.sender:提供以太币并拥有铸造cToken的账户;
  3. RETURN : 没有返回,出错时还原;

Solidity


Erc20 underlying = Erc20(0xToken...); // get a handle for the underlying asset contract
CErc20 cToken = CErc20(0x3FDA...); // get a handle for the corresponding cToken contract
underlying.approve(address(cToken), 100); // approve the transfer
assert(cToken.mint(100) == 0); // mint the cTokens and assert there is no error

Web3 1.0


const cToken = CEther.at(0x3FDB...);
await cToken.methods.mint().send({from: myAccount, value: 50});

 

2、赎回

 

赎回函数负责将基础资产从货币市场转移至用户,以交换之前铸造的cToken。基础资产赎回金额根据cToken的数量乘以当前汇率得出。赎回金额必须小于用户帐户的流动性以及市场的可用流动性。

赎回相当于Compound 协议的退出功能。

CErc20 / CEther


function redeem(uint redeemTokens) returns (uint)
  1. msg.sender : 赎回资金转移账户;
  2. redeemTokens : 要赎回的cToken数量;
  3. RETURN : 返回0表示成功,其它则是错误代码;

Solidity


CEther cToken = CEther(0x3FDB...);
require(cToken.redeem(7) == 0, "something went wrong");

Web3 1.0


const cToken = CErc20.at(0x3FDA...);
cToken.methods.redeem(1).send({from: ...});

 

3、赎回基础资产

 

赎回基础资产函数,负责将基础资产从货币市场转移给用户,以换取之前铸造的CToken。cToken赎回的数量是基础资产的金额除以当前汇率。赎回金额必须小于用户帐户的流动性和市场的可用流动性。

CErc20 / CEther


function redeemUnderlying(uint redeemAmount) returns (uint)
  1. msg.sender : 赎回资金转移账户;
  2. redeemAmount : 要赎回的基础资产金额;
  3. RETURN : 返回0表示成功,其它则是错误代码;

Solidity


CEther cToken = CEther(0x3FDB...);
require(cToken.redeemUnderlying(50) == 0, "something went wrong");

Web3 1.0


const cToken = CErc20.at(0x3FDA...);
cToken.methods.redeemUnderlying(10).send({from: ...});

 

4、借款

 

借款函数负责将资产从货币市场转移给用户,并创建一个借款余额,该余额根据资产的借款利率累积利息。

借款金额必须少于用户的借款能力以及市场的可用流动性。用户必须维持一个抵押品要求以避免清算。

请注意,借款人将收到一笔基础资产交易。对CEther来说,这将是以太币,因此借款人必须是可偿付的。

CErc20 / CEther


function borrow(uint borrowAmount) returns (uint)
  1. msg.sender : 借款资金转移账户;
  2. borrowAmount : 待借基础资产金额;
  3. RETURN :返回0表示成功,其它则是错误代码;

Solidity


CErc20 cToken = CErc20(0x3FDA...);
require(cToken.borrow(100) == 0, "got collateral?");

Web3 1.0


const cToken = CEther.at(0x3FDB...);
await cToken.methods.borrow(50).send({from: 0xMyAccount});

 

5、偿还借款

 

偿还函数负责将资产转移到货币市场,以减少用户的借款余额。

CErc20


function repayBorrow(uint repayAmount) returns (uint)
  1. msg.sender : 借用资产并应偿还借款的账户;
  2. repayAmount : 待偿还标的借款资产的金额,值-1 (即2^256 -1)可用于偿还全部金额;
  3. RETURN : 返回0表示成功,其它则是错误代码;

在提供资产之前,用户必须首先批准cToken以访问其代币余额;

CEther


function repayBorrow() payable
  1. msg.value (payable):偿还的以太币数量,单位为wei;
  2. msg.sender:借用资产,并应偿还借款的账户;
  3. RETURN : 没有return,出错时还原;

Solidity


CEther cToken = CEther(0x3FDB...);
require(cToken.repayBorrow.value(100)() == 0, "transfer approved?");

Web3 1.0


const cToken = CErc20.at(0x3FDA...);
cToken.methods.repayBorrow(10000).send({from: ...});

 

6、偿还Borrow Behalf

 

该偿还函数负责将资产转移到货币市场,以减少用户的借款余额。

CErc20


function repayBorrowBehalf(address borrower, uint repayAmount) returns (uint)
  1. msg.sender : 应偿还借款的账户;
  2. borrower : 借用待偿还资产的账户;
  3. repayAmount : 待偿还标的借款资产的金额,值-1 (即2^256 -1)可用于偿还全部金额;
  4. RETURN : 返回0表示成功,其它则是错误代码;

在提供资产之前,用户必须首先批准cToken以访问其代币余额;

CEther


function repayBorrowBehalf(address borrower) payable
  1. msg.value (payable):偿还的以太币数量,单位为wei;
  2. msg.sender:应偿还借款的账户;
  3. borrower : 借用偿还资产的账户;
  4. RETURN : 没有return,出错时还原;

Solidity


CEther cToken = CEther(0x3FDB...);
require(cToken.repayBorrowBehalf.value(100)(0xBorrower) == 0, "transfer approved?");

Web3 1.0


const cToken = CErc20.at(0x3FDA...);
await cToken.methods.repayBorrowBehalf(0xBorrower, 10000).send({from: 0xPayer});

 

7、清算借款

 

账户流动性为负的用户将被协议的其他用户清算,以使其账户流动性恢复为正(即高于抵押品要求)。当清算发生时,清算人可代表借款人偿还部分或全部未偿还借款,作为回报,清算人可获得借款人持有的抵押物,这被定义为清算激励。

清算人可将“清算账户”(即低于抵押品要求的账户)的任何未偿还借款的某一固定百分比结清。与v1不同的是,清算人必须与每个cToken合约进行互动,在这些合约中,他们希望偿还借款并扣押另一资产作为抵押品。当抵押品被扣押时,清算人被转移至cToken,他们可赎回这些抵押品,就像他们自己提供了资产一样。用户在将资金转入合约之前,必须先批准每个cToken合约,然后才能进行清算。

CErc20


function liquidateBorrow(address borrower, uint amount, address collateral) returns (uint)
  1. msg.sender : 通过偿还债务和扣押抵押品清算借款人的账户;
  2. borrower : 应清算的账户流动性为负的账户;
  3. repayAmount : 以标的借款资产为单位,待偿还的借款金额;
  4. cTokenCollateral : 清算人应扣押的借款人持有的cToken地址;
  5. RETURN : 返回0表示成功,其它则是错误代码;

在提供资产之前,用户必须首先批准cToken以访问其代币余额;

CEther


function liquidateBorrow(address borrower, address cTokenCollateral) payable
  1. msg.value (payable):待偿还且被转换为抵押品的以太币,单位为wei;
  2. msg.sender : 通过偿还债务和扣押抵押品,用于清算借款人的账户;
  3. borrower : 应清算的账户流动性为负的账户;
  4. cTokenCollateral :清算人应扣押的,借款人目前作为抵押品持有的cToken地址;
  5. RETURN : 没有return,出错时还原;

Solidity


CEther cToken = CEther(0x3FDB...);
CErc20 cTokenCollateral = CErc20(0x3FDA...);
require(cToken.liquidateBorrow.value(100)(0xBorrower, cTokenCollateral) == 0, "borrower underwater??");

Web3 1.0


const cToken = CErc20.at(0x3FDA...);
const cTokenCollateral = CEther.at(0x3FDB...);
await cToken.methods.liquidateBorrow(0xBorrower, 33, cTokenCollateral).send({from: 0xLiquidator});

 

8、故障信息

 

455556

9、兑换汇率

 

随着市场利息的增加,每个cToken都可转换成(不断增长的)基础资产。cToken与基础资产之间的汇率等于:


exchangeRate = (getCash() + totalBorrows() - totalReserves()) / totalSupply()

CErc20 / CEther


function exchangeRateCurrent() returns (uint)

RETURN : 当前汇率为无符号整数,按1e18缩放。

Solidity


CErc20 cToken = CToken(0x3FDA...);
uint exchangeRateMantissa = cToken.exchangeRateCurrent();

Web3 1.0


const cToken = CEther.at(0x3FDB...);
const exchangeRate = (await cToken.methods.exchangeRateCurrent().call()) / 1e18;

提示:注意使用call和send从链外调用该函数,则不会产生gas成本。

 

10、Get Cash

 

Cash是该cToken合约所拥有的基础资产余额。人们可查询这个市场目前可用的cash总额。

CErc20 / CEther


function getCash() returns (uint)

RETURN : 合约所拥有基础资产的数量。

Solidity


CErc20 cToken = CToken(0x3FDA...);
uint cash = cToken.getCash();

Web3 1.0


const cToken = CEther.at(0x3FDB...);
const cash = (await cToken.methods.getCash().call());

 

11、借款总额

 

借款总额是指市场目前借出的基础资产总金额,加上相应的利息金额。

CErc20 / CEther


function totalBorrowsCurrent() returns (uint)

RETURN : 加上利息的基础资产借款总额;

Solidity


CErc20 cToken = CToken(0x3FDA...);
uint borrows = cToken.totalBorrowsCurrent();

Web3 1.0


const cToken = CEther.at(0x3FDB...);
const borrows = (await cToken.methods.totalBorrowsCurrent().call());

 

12、借款余额

 

从协议中借款的用户,将根据当前借款利率支付累计利息。利息是每个区块累积计算的,我们可使用此函数获得用户(带利息)借款余额的当前值;

CErc20 / CEther


function borrowBalanceCurrent(address account) returns (uint)
  1. account : 借用资产的账户;
  2. RETURN : 用户当前的标的资产借款余额(含利息);

Solidity


CErc20 cToken = CToken(0x3FDA...);
uint borrows = cToken.borrowBalanceCurrent(msg.caller);

Web3 1.0


const cToken = CEther.at(0x3FDB...);
const borrows = await cToken.methods.borrowBalanceCurrent(account).call();

 

13、借款利率

 

在任何时候,人们都可以查询合约,以获得每个区块的当前借款利率。

CErc20 / CEther


function borrowRatePerBlock() returns (uint)

RETURN :当前借款利率为无符号整数,按1e18缩放。

Solidity


CErc20 cToken = CToken(0x3FDA...);
uint borrowRateMantissa = cToken.borrowRatePerBlock();

Web3 1.0


const cToken = CEther.at(0x3FDB...);
const borrowRate = (await cToken.methods.borrowRatePerBlock().call()) / 1e18;

14、总供给量

 

所谓总供给量,是指当前在这个cToken市场上流通的代币数量。它是cToken合约EIP-20接口的一部分。

CErc20 / CEther


function totalSupply() returns (uint)

RETURN : 市场流通的代币总数。

Solidity


CErc20 cToken = CToken(0x3FDA...);
uint tokens = cToken.totalSupply();

Web3 1.0


const cToken = CEther.at(0x3FDB...);
const tokens = (await cToken.methods.totalSupply().call());

 

15、供应余额

 

向协议提供资产的用户,将收到利息代币作为报酬。在任何给定时间,我们可通过汇率查询带息代币的价值。我们还可以查询特定用户拥有的代币数量,这是cToken合约EIP-20接口的一部分。

CErc20 / CEther


function balanceOf(address account) returns (uint)
  1. account : 获取代币余额的账户;
  2. RETURN : 帐户当前拥有的代币数;

Solidity


CErc20 cToken = CToken(0x3FDA...);
uint tokens = cToken.balanceOf(msg.caller);

Web3 1.0


const cToken = CEther.at(0x3FDB...);
const tokens = await cToken.methods.balanceOf(account).call();

 

16、基础资产供应余额

 

CToken还有一种方便的方法,可根据基础资产金额(即供应余额乘以汇率)来确定供应余额。

CErc20 / CEther


function balanceOfUnderlying(address account) returns (uint)
  1. account : 要获取基础资产余额的帐户;
  2. RETURN : 帐户当前拥有的基础资产金额;

Solidity


CErc20 cToken = CToken(0x3FDA...);
uint tokens = cToken.balanceOfUnderlying(msg.caller);

Web3 1.0


const cToken = CEther.at(0x3FDB...);
const tokens = await cToken.methods.balanceOfUnderlying(account).call();

 

17、供应率

 

在任何时候,人们都可以查询合约,以获得每个区块的当前供应率。供应率由借款利率、储备金率以及借款总额得出。

CErc20 / CEther


function supplyRatePerBlock() returns (uint)

RETURN : 当前供应率为无符号整数,按1e18缩放。

Solidity


CErc20 cToken = CToken(0x3FDA...);
uint supplyRateMantissa = cToken.supplyRatePerBlock();

Web3 1.0


const cToken = CEther.at(0x3FDB...);
const supplyRate = (await cToken.methods.supplyRatePerBlock().call()) / 1e18;

 

18、总储备金

 

储备金是协议本身的权益,以便为其运作提供资金。储备金也构成了cash的一部分,可用于贷给市场上的借款人。借款人的一小部分利息计入协议,而它是由准备金率决定的。

CErc20 / CEther


function totalReserves() returns (uint)

RETURN : 协议持有的储备金总额;

Solidity


CErc20 cToken = CToken(0x3FDA...);
uint reserves = cToken.totalReserves();

Web3 1.0


const cToken = CEther.at(0x3FDB...);
const reserves = (await cToken.methods.totalReserves().call());

 

19、储备金率

 

储备金率定义了应计入储备金的一小部分利息。

CErc20 / CEther


function reserveFactorMantissa() returns (uint)

RETURN : 当前储备金率为无符号整数,按1e18缩放。

Solidity


CErc20 cToken = CToken(0x3FDA...);
uint reserveFactorMantissa = cToken.reserveFactorMantissa();

Web3 1.0


const cToken = CEther.at(0x3FDB...);
const reserveFactor = (await cToken.methods.reserveFactorMantissa().call()) / 1e18;

声明:登载此文出于传递更多信息之目的,观点仅代表作者本人,绝不代表Hi区块链赞同其观点或证实其描述。

提示:投资有风险,入市须谨慎。本资讯不作为投资理财建议。