20201015 Compoundのコントラクトを読む
#tadashim
前回
20201001 Compoundのコントラクトを読む
Github: https://github.com/compound-finance/compound-protocol
公式ドキュメント: https://compound.finance/docs#getting-started
CEther.sol
〜前回見たところ〜
CEtherコントラクト
CEtherはEtherをラップしたCToken
CTokenコントラクトを継承
コンストラクタ
admin アドレスが指定できるようになっている
InterestRateModelコントラクトのアドレスを指定
これにより利息のレートが変更できるようになっていると推測
Comptrollerコントラクトのアドレスを指定
code:solidity
constructor(ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_,
address payable admin_) public {
// Creator of the contract is admin during initialization
admin = msg.sender;
initialize(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);
// Set the proper admin now that initialization is done
admin = admin_;
}
mint関数
送信者がETHを送金しつつmint関数を呼び出すと、cETHが生成されて送信者に返される(ETHとcETHを交換している)。cETH(CToken)は債権トークンであり、ERC20トークンとして使用できる。
mintInternal関数を呼び出している
code:solidity
function mint() external payable {
(uint err,) = mintInternal(msg.value);
requireNoError(err, "mint failed");
}
redeem関数
パラメータで指定した数量のcETHが償還され、対応する数量のETHが送信者に返却される
redeemInternal関数を呼び出している
code:solidity
function redeem(uint redeemTokens) external returns (uint) {
return redeemInternal(redeemTokens);
}
redeemUnderlying関数
パラメータで指定した数量のETHが返却され、対応するcETHが償還される
redeemUnderlyingInternal関数を呼び出している
code:solidity
function redeemUnderlying(uint redeemAmount) external returns (uint) {
return redeemUnderlyingInternal(redeemAmount);
}
borrow関数
パラメータで指定した数量のETHを借りる
borrowInternal関数を呼び出している
code:solidity
function borrow(uint borrowAmount) external returns (uint) {
return borrowInternal(borrowAmount);
}
repayBorrow関数
送信者はETHを送金しつつrepayBorrow関数を呼び出すことで、Compoundから借りたETHを返却できる
repayBorrowInternal関数を呼び出している
code:solidity
function repayBorrow() external payable {
(uint err,) = repayBorrowInternal(msg.value);
requireNoError(err, "repayBorrow failed");
}
〜前回ここまで〜
repayBorrowBehalf関数
送信者はETHを送金しつつrepayBorrowBehalf関数を呼び出すことで、パラメータで指定したアドレスを持つ借り手の借金を返済する
repayBorrowBehalfInternal関数を呼び出している
code:solidity
function repayBorrowBehalf(address borrower) external payable {
(uint err,) = repayBorrowBehalfInternal(borrower, msg.value);
requireNoError(err, "repayBorrowBehalf failed");
}
liquidateBorrow関数
借り手の担保を精算する
差し押さえられた担保は清算人に譲渡される(清算人はETHを送金しつつ、この関数を呼び出す)
パラメータ
借り手のアドレス
精算するcToken
liquidateBorrowInternal関数を呼び出している
code:solidity
function liquidateBorrow(address borrower, CToken cTokenCollateral) external payable {
(uint err,) = liquidateBorrowInternal(borrower, msg.value, cTokenCollateral);
requireNoError(err, "liquidateBorrow failed");
}
フォールバック関数
無名関数で、コントラクトの関数呼び出しが行われたが関数シグネチャが見つからない場合に代わりに呼ばれる
mint関数と同じ動作をする
code:solidity
function () external payable {
(uint err,) = mintInternal(msg.value);
requireNoError(err, "mint failed");
}
getCashPrior関数
このCEtherコントラクトにロックされているETH建ての残高を取得できる
internalのため、コントラクト外部からは呼べない
code:solidity
function getCashPrior() internal view returns (uint) {
(MathError err, uint startingBalance) = subUInt(address(this).balance, msg.value);
require(err == MathError.NO_ERROR);
return startingBalance;
}
doTransferIn関数
入金時の正常性チェック
トランザクションを呼び出したアドレスとパラメータとして渡されたfromアドレスが一緒か?
送金されたETHの額とパラメータとして渡されたamountが一緒か?
internalのため、コントラクト外部からは呼べない
code:solidity
function doTransferIn(address from, uint amount) internal returns (uint) {
// Sanity checks
require(msg.sender == from, "sender mismatch");
require(msg.value == amount, "value mismatch");
return amount;
}
doTransferOut関数
送金を実行
パラメータ
宛先アドレス
送金額
internalのため、コントラクト外部からは呼べない
code:solidity
function doTransferOut(address payable to, uint amount) internal {
/* Send the Ether, with minimal gas and revert on failure */
to.transfer(amount);
}
requireNoError関数
エラー処理
パラメータ
エラーコード
エラーメッセージ
stringの渡されたエラーメッセージをbytesに変換して処理している
internalのため、コントラクト外部からは呼べない
code:solidity
function requireNoError(uint errCode, string memory message) internal pure {
if (errCode == uint(Error.NO_ERROR)) {
return;
}
bytes memory fullMessage = new bytes(bytes(message).length + 5);
uint i;
for (i = 0; i < bytes(message).length; i++) {
fullMessagei = bytes(message)i;
}
fullMessagei+0 = byte(uint8(32));
fullMessagei+1 = byte(uint8(40));
fullMessagei+2 = byte(uint8(48 + ( errCode / 10 )));
fullMessagei+3 = byte(uint8(48 + ( errCode % 10 )));
fullMessagei+4 = byte(uint8(41));
require(errCode == uint(Error.NO_ERROR), string(fullMessage));
}