¡El código fuente de este contrato está verificado!
Metadatos del Contrato
Compilador
0.8.15+commit.e14f2714
Idioma
Solidity
Código Fuente del Contrato
Archivo 1 de 10: BaseBulker.sol
// SPDX-License-Identifier: BUSL-1.1pragmasolidity 0.8.15;import"../CometInterface.sol";
import"../IERC20NonStandard.sol";
import"../IWETH9.sol";
/**
* @dev Interface for claiming rewards from the CometRewards contract
*/interfaceIClaimable{
functionclaim(address comet, address src, bool shouldAccrue) external;
functionclaimTo(address comet, address src, address to, bool shouldAccrue) external;
}
/**
* @title Compound's Bulker contract
* @notice Executes multiple Comet-related actions in a single transaction
* @author Compound
* @dev Note: Only intended to be used on EVM chains that have a native token and wrapped native token that implements the IWETH interface
*/contractBaseBulker{
/** Custom events **/eventAdminTransferred(addressindexed oldAdmin, addressindexed newAdmin);
/** General configuration constants **//// @notice The admin of the Bulker contractaddresspublic admin;
/// @notice The address of the wrapped representation of the chain's native assetaddresspayablepublicimmutable wrappedNativeToken;
/** Actions **//// @notice The action for supplying an asset to Cometbytes32publicconstant ACTION_SUPPLY_ASSET ="ACTION_SUPPLY_ASSET";
/// @notice The action for supplying a native asset (e.g. ETH on Ethereum mainnet) to Cometbytes32publicconstant ACTION_SUPPLY_NATIVE_TOKEN ="ACTION_SUPPLY_NATIVE_TOKEN";
/// @notice The action for transferring an asset within Cometbytes32publicconstant ACTION_TRANSFER_ASSET ="ACTION_TRANSFER_ASSET";
/// @notice The action for withdrawing an asset from Cometbytes32publicconstant ACTION_WITHDRAW_ASSET ="ACTION_WITHDRAW_ASSET";
/// @notice The action for withdrawing a native asset from Cometbytes32publicconstant ACTION_WITHDRAW_NATIVE_TOKEN ="ACTION_WITHDRAW_NATIVE_TOKEN";
/// @notice The action for claiming rewards from the Comet rewards contractbytes32publicconstant ACTION_CLAIM_REWARD ="ACTION_CLAIM_REWARD";
/** Custom errors **/errorInvalidAddress();
errorInvalidArgument();
errorFailedToSendNativeToken();
errorTransferInFailed();
errorTransferOutFailed();
errorUnauthorized();
errorUnhandledAction();
/**
* @notice Construct a new BaseBulker instance
* @param admin_ The admin of the Bulker contract
* @param wrappedNativeToken_ The address of the wrapped representation of the chain's native asset
**/constructor(address admin_, addresspayable wrappedNativeToken_) {
admin = admin_;
wrappedNativeToken = wrappedNativeToken_;
}
/**
* @notice Fallback for receiving native token. Needed for ACTION_WITHDRAW_NATIVE_TOKEN
*/receive() externalpayable{}
/**
* @notice A public function to sweep accidental ERC-20 transfers to this contract
* @dev Note: Make sure to check that the asset being swept out is not malicious
* @param recipient The address that will receive the swept funds
* @param asset The address of the ERC-20 token to sweep
*/functionsweepToken(address recipient, address asset) external{
if (msg.sender!= admin) revert Unauthorized();
uint256 balance = IERC20NonStandard(asset).balanceOf(address(this));
doTransferOut(asset, recipient, balance);
}
/**
* @notice A public function to sweep accidental native token transfers to this contract
* @param recipient The address that will receive the swept funds
*/functionsweepNativeToken(address recipient) external{
if (msg.sender!= admin) revert Unauthorized();
uint256 balance =address(this).balance;
(bool success, ) = recipient.call{ value: balance }("");
if (!success) revert FailedToSendNativeToken();
}
/**
* @notice Transfers the admin rights to a new address
* @param newAdmin The address that will become the new admin
*/functiontransferAdmin(address newAdmin) external{
if (msg.sender!= admin) revert Unauthorized();
if (newAdmin ==address(0)) revert InvalidAddress();
address oldAdmin = admin;
admin = newAdmin;
emit AdminTransferred(oldAdmin, newAdmin);
}
/**
* @notice Executes a list of actions in order
* @param actions The list of actions to execute in order
* @param data The list of calldata to use for each action
*/functioninvoke(bytes32[] calldata actions, bytes[] calldata data) externalpayable{
if (actions.length!= data.length) revert InvalidArgument();
uint unusedNativeToken =msg.value;
for (uint i =0; i < actions.length; ) {
bytes32 action = actions[i];
if (action == ACTION_SUPPLY_ASSET) {
(address comet, address to, address asset, uint amount) =abi.decode(data[i], (address, address, address, uint));
supplyTo(comet, to, asset, amount);
} elseif (action == ACTION_SUPPLY_NATIVE_TOKEN) {
(address comet, address to, uint amount) =abi.decode(data[i], (address, address, uint));
uint256 nativeTokenUsed = supplyNativeTokenTo(comet, to, amount);
unusedNativeToken -= nativeTokenUsed;
} elseif (action == ACTION_TRANSFER_ASSET) {
(address comet, address to, address asset, uint amount) =abi.decode(data[i], (address, address, address, uint));
transferTo(comet, to, asset, amount);
} elseif (action == ACTION_WITHDRAW_ASSET) {
(address comet, address to, address asset, uint amount) =abi.decode(data[i], (address, address, address, uint));
withdrawTo(comet, to, asset, amount);
} elseif (action == ACTION_WITHDRAW_NATIVE_TOKEN) {
(address comet, address to, uint amount) =abi.decode(data[i], (address, address, uint));
withdrawNativeTokenTo(comet, to, amount);
} elseif (action == ACTION_CLAIM_REWARD) {
(address comet, address rewards, address src, bool shouldAccrue) =abi.decode(data[i], (address, address, address, bool));
claimReward(comet, rewards, src, shouldAccrue);
} else {
handleAction(action, data[i]);
}
unchecked { i++; }
}
// Refund unused native token back to msg.senderif (unusedNativeToken >0) {
(bool success, ) =msg.sender.call{ value: unusedNativeToken }("");
if (!success) revert FailedToSendNativeToken();
}
}
/**
* @notice Handles any actions not handled by the BaseBulker implementation
* @dev Note: Meant to be overridden by contracts that extend BaseBulker and want to support more actions
*/functionhandleAction(bytes32 action, bytescalldata data) virtualinternal{
revert UnhandledAction();
}
/**
* @notice Supplies an asset to a user in Comet
* @dev Note: This contract must have permission to manage msg.sender's Comet account
*/functionsupplyTo(address comet, address to, address asset, uint amount) internal{
CometInterface(comet).supplyFrom(msg.sender, to, asset, amount);
}
/**
* @notice Wraps the native token and supplies wrapped native token to a user in Comet
* @return The amount of the native token wrapped and supplied to Comet
* @dev Note: Supports `amount` of `uint256.max` implies max only for base asset
*/functionsupplyNativeTokenTo(address comet, address to, uint amount) internalreturns (uint256) {
uint256 supplyAmount = amount;
if (wrappedNativeToken == CometInterface(comet).baseToken()) {
if (amount ==type(uint256).max)
supplyAmount = CometInterface(comet).borrowBalanceOf(msg.sender);
}
IWETH9(wrappedNativeToken).deposit{ value: supplyAmount }();
IWETH9(wrappedNativeToken).approve(comet, supplyAmount);
CometInterface(comet).supplyFrom(address(this), to, wrappedNativeToken, supplyAmount);
return supplyAmount;
}
/**
* @notice Transfers an asset to a user in Comet
* @dev Note: This contract must have permission to manage msg.sender's Comet account
*/functiontransferTo(address comet, address to, address asset, uint amount) internal{
CometInterface(comet).transferAssetFrom(msg.sender, to, asset, amount);
}
/**
* @notice Withdraws an asset to a user in Comet
* @dev Note: This contract must have permission to manage msg.sender's Comet account
*/functionwithdrawTo(address comet, address to, address asset, uint amount) internal{
CometInterface(comet).withdrawFrom(msg.sender, to, asset, amount);
}
/**
* @notice Withdraws wrapped native token from Comet, unwraps it to the native token, and transfers it to a user
* @dev Note: This contract must have permission to manage msg.sender's Comet account
* @dev Note: Supports `amount` of `uint256.max` only for the base asset. Should revert for a collateral asset
*/functionwithdrawNativeTokenTo(address comet, address to, uint amount) internal{
uint256 withdrawAmount = amount;
if (wrappedNativeToken == CometInterface(comet).baseToken()) {
if (amount ==type(uint256).max)
withdrawAmount = CometInterface(comet).balanceOf(msg.sender);
}
CometInterface(comet).withdrawFrom(msg.sender, address(this), wrappedNativeToken, withdrawAmount);
IWETH9(wrappedNativeToken).withdraw(withdrawAmount);
(bool success, ) = to.call{ value: withdrawAmount }("");
if (!success) revert FailedToSendNativeToken();
}
/**
* @notice Claims rewards for a user
*/functionclaimReward(address comet, address rewards, address src, bool shouldAccrue) internal{
IClaimable(rewards).claim(comet, src, shouldAccrue);
}
/**
* @notice Similar to ERC-20 transfer, except it properly handles `transferFrom` from non-standard ERC-20 tokens
* @param asset The ERC-20 token to transfer in
* @param from The address to transfer from
* @param amount The amount of the token to transfer
* @dev Note: This does not check that the amount transferred in is actually equals to the amount specified (e.g. fee tokens will not revert)
* @dev Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
*/functiondoTransferIn(address asset, addressfrom, uint amount) internal{
IERC20NonStandard(asset).transferFrom(from, address(this), amount);
bool success;
assembly {
switchreturndatasize()
case0 { // This is a non-standard ERC-20
success :=not(0) // set success to true
}
case32 { // This is a compliant ERC-20returndatacopy(0, 0, 32)
success :=mload(0) // Set `success = returndata` of override external call
}
default { // This is an excessively non-compliant ERC-20, revert.revert(0, 0)
}
}
if (!success) revert TransferInFailed();
}
/**
* @notice Similar to ERC-20 transfer, except it properly handles `transfer` from non-standard ERC-20 tokens
* @param asset The ERC-20 token to transfer out
* @param to The recipient of the token transfer
* @param amount The amount of the token to transfer
* @dev Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
*/functiondoTransferOut(address asset, address to, uint amount) internal{
IERC20NonStandard(asset).transfer(to, amount);
bool success;
assembly {
switchreturndatasize()
case0 { // This is a non-standard ERC-20
success :=not(0) // set success to true
}
case32 { // This is a compliant ERC-20returndatacopy(0, 0, 32)
success :=mload(0) // Set `success = returndata` of override external call
}
default { // This is an excessively non-compliant ERC-20, revert.revert(0, 0)
}
}
if (!success) revert TransferOutFailed();
}
}
// SPDX-License-Identifier: BUSL-1.1pragmasolidity 0.8.15;import"./CometConfiguration.sol";
import"./CometStorage.sol";
import"./CometMath.sol";
abstractcontractCometCoreisCometConfiguration, CometStorage, CometMath{
structAssetInfo {
uint8 offset;
address asset;
address priceFeed;
uint64 scale;
uint64 borrowCollateralFactor;
uint64 liquidateCollateralFactor;
uint64 liquidationFactor;
uint128 supplyCap;
}
/** Internal constants **//// @dev The max number of assets this contract is hardcoded to support/// Do not change this variable without updating all the fields throughout the contract,// including the size of UserBasic.assetsIn and corresponding integer conversions.uint8internalconstant MAX_ASSETS =15;
/// @dev The max number of decimals base token can have/// Note this cannot just be increased arbitrarily.uint8internalconstant MAX_BASE_DECIMALS =18;
/// @dev The max value for a collateral factor (1)uint64internalconstant MAX_COLLATERAL_FACTOR = FACTOR_SCALE;
/// @dev Offsets for specific actions in the pause flag bit arrayuint8internalconstant PAUSE_SUPPLY_OFFSET =0;
uint8internalconstant PAUSE_TRANSFER_OFFSET =1;
uint8internalconstant PAUSE_WITHDRAW_OFFSET =2;
uint8internalconstant PAUSE_ABSORB_OFFSET =3;
uint8internalconstant PAUSE_BUY_OFFSET =4;
/// @dev The decimals required for a price feeduint8internalconstant PRICE_FEED_DECIMALS =8;
/// @dev 365 days * 24 hours * 60 minutes * 60 secondsuint64internalconstant SECONDS_PER_YEAR =31_536_000;
/// @dev The scale for base tracking accrualuint64internalconstant BASE_ACCRUAL_SCALE =1e6;
/// @dev The scale for base index (depends on time/rate scales, not base token)uint64internalconstant BASE_INDEX_SCALE =1e15;
/// @dev The scale for prices (in USD)uint64internalconstant PRICE_SCALE =uint64(10** PRICE_FEED_DECIMALS);
/// @dev The scale for factorsuint64internalconstant FACTOR_SCALE =1e18;
/**
* @notice Determine if the manager has permission to act on behalf of the owner
* @param owner The owner account
* @param manager The manager account
* @return Whether or not the manager has permission
*/functionhasPermission(address owner, address manager) publicviewreturns (bool) {
return owner == manager || isAllowed[owner][manager];
}
/**
* @dev The positive present supply balance if positive or the negative borrow balance if negative
*/functionpresentValue(int104 principalValue_) internalviewreturns (int256) {
if (principalValue_ >=0) {
return signed256(presentValueSupply(baseSupplyIndex, uint104(principalValue_)));
} else {
return-signed256(presentValueBorrow(baseBorrowIndex, uint104(-principalValue_)));
}
}
/**
* @dev The principal amount projected forward by the supply index
*/functionpresentValueSupply(uint64 baseSupplyIndex_, uint104 principalValue_) internalpurereturns (uint256) {
returnuint256(principalValue_) * baseSupplyIndex_ / BASE_INDEX_SCALE;
}
/**
* @dev The principal amount projected forward by the borrow index
*/functionpresentValueBorrow(uint64 baseBorrowIndex_, uint104 principalValue_) internalpurereturns (uint256) {
returnuint256(principalValue_) * baseBorrowIndex_ / BASE_INDEX_SCALE;
}
/**
* @dev The positive principal if positive or the negative principal if negative
*/functionprincipalValue(int256 presentValue_) internalviewreturns (int104) {
if (presentValue_ >=0) {
return signed104(principalValueSupply(baseSupplyIndex, uint256(presentValue_)));
} else {
return-signed104(principalValueBorrow(baseBorrowIndex, uint256(-presentValue_)));
}
}
/**
* @dev The present value projected backward by the supply index (rounded down)
* Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals.
*/functionprincipalValueSupply(uint64 baseSupplyIndex_, uint256 presentValue_) internalpurereturns (uint104) {
return safe104((presentValue_ * BASE_INDEX_SCALE) / baseSupplyIndex_);
}
/**
* @dev The present value projected backward by the borrow index (rounded up)
* Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals.
*/functionprincipalValueBorrow(uint64 baseBorrowIndex_, uint256 presentValue_) internalpurereturns (uint104) {
return safe104((presentValue_ * BASE_INDEX_SCALE + baseBorrowIndex_ -1) / baseBorrowIndex_);
}
}
Código Fuente del Contrato
Archivo 4 de 10: CometExtInterface.sol
// SPDX-License-Identifier: BUSL-1.1pragmasolidity 0.8.15;import"./CometCore.sol";
/**
* @title Compound's Comet Ext Interface
* @notice An efficient monolithic money market protocol
* @author Compound
*/abstractcontractCometExtInterfaceisCometCore{
errorBadAmount();
errorBadNonce();
errorBadSignatory();
errorInvalidValueS();
errorInvalidValueV();
errorSignatureExpired();
functionallow(address manager, bool isAllowed) virtualexternal;
functionallowBySig(address owner, address manager, bool isAllowed, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) virtualexternal;
functioncollateralBalanceOf(address account, address asset) virtualexternalviewreturns (uint128);
functionbaseTrackingAccrued(address account) virtualexternalviewreturns (uint64);
functionbaseAccrualScale() virtualexternalviewreturns (uint64);
functionbaseIndexScale() virtualexternalviewreturns (uint64);
functionfactorScale() virtualexternalviewreturns (uint64);
functionpriceScale() virtualexternalviewreturns (uint64);
functionmaxAssets() virtualexternalviewreturns (uint8);
functiontotalsBasic() virtualexternalviewreturns (TotalsBasic memory);
functionversion() virtualexternalviewreturns (stringmemory);
/**
* ===== ERC20 interfaces =====
* Does not include the following functions/events, which are defined in `CometMainInterface` instead:
* - function decimals() virtual external view returns (uint8)
* - function totalSupply() virtual external view returns (uint256)
* - function transfer(address dst, uint amount) virtual external returns (bool)
* - function transferFrom(address src, address dst, uint amount) virtual external returns (bool)
* - function balanceOf(address owner) virtual external view returns (uint256)
* - event Transfer(address indexed from, address indexed to, uint256 amount)
*/functionname() virtualexternalviewreturns (stringmemory);
functionsymbol() virtualexternalviewreturns (stringmemory);
/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved (-1 means infinite)
* @return Whether or not the approval succeeded
*/functionapprove(address spender, uint256 amount) virtualexternalreturns (bool);
/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent (-1 means infinite)
*/functionallowance(address owner, address spender) virtualexternalviewreturns (uint256);
eventApproval(addressindexed owner, addressindexed spender, uint256 amount);
}