编译器
0.8.20+commit.a1b79de6
文件 1 的 12:Address.sol
pragma solidity ^0.8.20;
library Address {
error AddressInsufficientBalance(address account);
error AddressEmptyCode(address target);
error FailedInnerCall();
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
文件 2 的 12:Doubler.sol
pragma solidity ^0.8.20;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/utils/ReentrancyGuard.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import './interfaces/IFastPriceFeed.sol';
import './interfaces/IDoublerFactory.sol';
import './interfaces/IDoubler.sol';
import './interfaces/IRBToken.sol';
import './interfaces/IWETH.sol';
contract Doubler is IDoubler, ReentrancyGuard {
using SafeERC20 for IERC20;
uint16 private constant _slip = 50;
uint16 private constant _perMil = 1000;
address private _factory;
address private _fastPriceFeed;
Pool private _pool;
mapping(address => uint256) private _lastBlockCalled;
mapping(address => uint256) private _userExtraBToken;
constructor(address _initParent) {
_factory = _initParent;
}
function initialize(address _initFastPriceFeed, Pool memory _initPool) external {
if (_factory != msg.sender) revert E_Ownable();
_checkPoolParam(_initPool);
_fastPriceFeed = _initFastPriceFeed;
_pool = _initPool;
}
modifier onlyOwner() {
if (IDoublerFactory(_factory).getFactoryOwner() != msg.sender) revert E_Ownable();
_;
}
modifier onlyOnce() {
if (_pool.endPrice > 0 || _pool.startTime > block.timestamp || _pool.endTime < block.timestamp)
revert E_Disable();
if (_lastBlockCalled[tx.origin] >= block.number) revert E_BlockOnce();
_;
_lastBlockCalled[tx.origin] = block.number;
}
function getPool() external view returns (Pool memory) {
return _pool;
}
function getUserExtraBToken(address _to) external view returns(uint256) {
return _userExtraBToken[_to];
}
function _checkPoolParam(Pool memory _pl) internal pure {
if (_pl.inputFee > 20) revert E_FeeLimit();
if (_pl.withdrawFee > 20) revert E_FeeLimit();
if (_pl.creator == address(0x0)) revert E_ZeroAddr();
}
function updatePool(MPool calldata _updatePl) external onlyOwner {
if (_pool.endPrice != 0) revert E_PoolEnd();
if (_pool.endTime != _updatePl.endTime) {
if (_updatePl.endTime <= _pool.endTime || block.timestamp < _pool.endTime - 7 days) revert E_EndTime();
if (_getCurPrice(_pool.asset) >= _getAssetAvg(_pool.asset)) revert E_PriceLimit();
}
_pool.inputFee = _updatePl.inputFee;
_pool.withdrawFee = _updatePl.withdrawFee;
_pool.creator = _updatePl.creator;
_pool.endTime = _updatePl.endTime;
_checkPoolParam(_pool);
emit UpdatePool(_pool.asset, _pool.creator, _pool.inputFee, _pool.withdrawFee, _pool.endTime);
}
function _getAssetBalance(address _asset) private view returns (uint256) {
return IERC20(_asset).balanceOf(address(this));
}
function _getSrvFeeAddr(address _creator) internal view returns (address[] memory srvFeeAddr) {
srvFeeAddr = new address[](2);
srvFeeAddr[0] = _creator;
srvFeeAddr[1] = IDoublerFactory(_factory).getEcoAddr();
}
function _getAssetAvg(address _asset) private view returns (uint256) {
uint256 assetTotal = _getAssetBalance(_asset);
if (assetTotal == 0) {
return 0;
}
return (IERC20(_pool.cToken).totalSupply() * _getUnitSize(_pool.asset)) / assetTotal;
}
function _getCurPrice(address _asset) internal view returns (uint256) {
return IFastPriceFeed(_fastPriceFeed).getPrice(_asset);
}
function _getUnitSize(address _asset) internal view returns (uint256) {
return 10 ** IERC20Metadata(_asset).decimals();
}
function inputEth(uint256 _qAmount, address _to) external payable nonReentrant onlyOnce {
if (!_pool.isNative) revert E_Asset();
if (msg.value != _qAmount) revert E_Balance();
_input(_qAmount, _to, true);
}
function input(uint256 _qAmount, address _to) external nonReentrant onlyOnce {
if (IERC20(_pool.asset).balanceOf(msg.sender) < _qAmount) revert E_Balance();
_input(_qAmount, _to, false);
}
function _checkInputQAmount(
uint256 _qAmount,
uint256 _curPrice,
uint256 _assetUnitSize,
uint256 _lowerOfInputMaximum
) internal view {
uint256 inputValue = (_curPrice * _qAmount) / _assetUnitSize;
uint256 inputMax = (_curPrice * _getAssetBalance(_pool.asset)) / _assetUnitSize / 100;
inputMax = inputMax > _lowerOfInputMaximum ? inputMax : _lowerOfInputMaximum;
if (inputValue < 1 ether || inputValue > inputMax) revert E_InputLimit();
}
function _input(uint256 _qAmount, address _to, bool _isNative) internal {
_rebaseCToken();
uint256 curPrice = _getCurPrice(_pool.asset);
uint256 avg = _getAssetAvg(_pool.asset);
uint256 assetUnitSize = _getUnitSize(_pool.asset);
_checkInputQAmount(_qAmount, curPrice, assetUnitSize, _pool.lowerOfInputMaximum);
uint256 bAmount;
uint256 cAmount;
uint256 bTotal = IERC20(_pool.bToken).totalSupply();
uint256 cTotal = IERC20(_pool.cToken).totalSupply();
uint256 extBAmount;
if (cTotal == 0) {
cAmount = (curPrice * _qAmount) / assetUnitSize;
bAmount = cAmount / 10;
avg = curPrice;
} else {
uint256 stmPrice = avg;
if (curPrice <= avg) {
stmPrice = curPrice;
extBAmount = (curPrice * _qAmount - (curPrice * curPrice * _qAmount) / avg) / assetUnitSize;
_userExtraBToken[_to] += extBAmount;
}
cAmount = (stmPrice * _qAmount) / assetUnitSize;
bAmount = extBAmount + (cAmount * bTotal) / cTotal;
}
if (_isNative) {
IWETH(_pool.asset).deposit{ value: msg.value }();
} else {
IERC20(_pool.asset).safeTransferFrom(msg.sender, address(this), _qAmount);
}
_mintBCToken(_to, bAmount, cAmount);
emit Input(_pool.asset, _pool.id, _to, _qAmount, bAmount, cAmount, extBAmount);
emit PoolStream(_pool.asset, _pool.id, _qAmount, bTotal, cTotal, curPrice, avg);
}
function _mintBCToken(address _to, uint256 _bAmount, uint256 _cAmount) internal {
IRBToken(_pool.bToken).mintWithFee(_to, _bAmount, _getSrvFeeAddr(_pool.creator), _pool.inputFee);
IRBToken(_pool.cToken).mint(_to, _cAmount);
}
function _getWithdrawAssetAmount(
uint256 _bAmount,
uint256 _cAmount,
uint256 _bTotal,
uint256 _cTotal,
uint256 _curPrice,
uint256 _avgPrice
) internal view returns (uint256 assetAmount) {
uint256 assetUnitSize = _getUnitSize(_pool.asset);
if (_curPrice >= _avgPrice) {
uint256 profit = (((_getAssetBalance(_pool.asset) * _curPrice) / assetUnitSize - _cTotal) * _bAmount) /
_bTotal;
assetAmount = ((_cAmount + profit) * assetUnitSize) / _curPrice;
} else {
assetAmount = (_cAmount * assetUnitSize) / _avgPrice;
}
}
function _getSpendBAmount(
uint256 _cAmount,
uint256 _bTotal,
uint256 _cTotal
) internal view returns (uint256 spendBAmount) {
spendBAmount = (_cAmount * _bTotal) / _cTotal;
uint256 uBTokenBalance = IERC20(_pool.bToken).balanceOf(msg.sender);
if (_pool.endPrice == 0 && _cTotal == _cAmount && spendBAmount > uBTokenBalance) {
if (spendBAmount - uBTokenBalance <= _getUnitSize(_pool.bToken) / 10) spendBAmount = uBTokenBalance;
}
if (IERC20(_pool.cToken).balanceOf(msg.sender) < _cAmount) revert E_Balance();
if (uBTokenBalance < spendBAmount) revert E_Balance();
}
function _withdraw(
uint256 _curPrice,
uint256 _avgPrice,
uint256 _bAmount,
uint256 _cAmount,
uint256 _bTotal,
uint256 _cTotal
) internal returns (uint256 assetAmount, uint256 srvFee) {
if (
IRBToken(_pool.bToken).balanceOf(msg.sender) < _bAmount ||
IRBToken(_pool.cToken).balanceOf(msg.sender) < _cAmount
) revert E_Balance();
assetAmount = _getWithdrawAssetAmount(_bAmount, _cAmount, _bTotal, _cTotal, _curPrice, _avgPrice);
uint256 qAmount = _getAssetBalance(_pool.asset);
if (qAmount <= assetAmount) {
assetAmount = _getAssetBalance(_pool.asset);
}
if (_cAmount > 0) {
IRBToken(_pool.cToken).burnFrom(msg.sender, _cAmount);
}
if (_bAmount > 0) {
IRBToken(_pool.bToken).burnFrom(msg.sender, _bAmount);
}
srvFee = (assetAmount * _pool.withdrawFee) / _perMil;
IERC20(_pool.asset).safeTransfer(_pool.creator, srvFee / 2);
address ecoAddr = IDoublerFactory(_factory).getEcoAddr();
IERC20(_pool.asset).safeTransfer(ecoAddr, srvFee - srvFee / 2);
IERC20(_pool.asset).safeTransfer(msg.sender, assetAmount - srvFee);
emit Withdraw(_pool.asset, _pool.id, msg.sender, _cAmount, _bAmount, assetAmount);
emit PoolStream(_pool.asset, _pool.id, qAmount, _bTotal, _cTotal, _curPrice, _avgPrice);
}
function claim() external nonReentrant {
if (_pool.endPrice == 0) revert E_PoolEnd();
uint256 bAmount = IERC20(_pool.bToken).balanceOf(msg.sender);
uint256 cAmount = IERC20(_pool.cToken).balanceOf(msg.sender);
uint256 curPrice = _pool.endPrice;
uint256 avgPrice = _getAssetAvg(_pool.asset);
uint256 bTotal = IERC20(_pool.bToken).totalSupply();
uint256 cTotal = IERC20(_pool.cToken).totalSupply();
_withdraw(curPrice, avgPrice, bAmount, cAmount, bTotal, cTotal);
}
function withdraw(uint256 _cAmount, uint256 _qAmount, uint16 _clientSlip) external nonReentrant onlyOnce {
_rebaseCToken();
uint256 curPrice = _getCurPrice(_pool.asset);
uint256 avgPrice = _getAssetAvg(_pool.asset);
uint256 bTotal = IERC20(_pool.bToken).totalSupply();
uint256 cTotal = IERC20(_pool.cToken).totalSupply();
uint256 bAmount = _getSpendBAmount(_cAmount, bTotal, cTotal);
(uint256 assetAmount, uint256 srvFee) = _withdraw(curPrice, avgPrice, bAmount, _cAmount, bTotal, cTotal);
_checkWithdrawLimit(_pool.asset, curPrice);
_checkAmountSlip(_qAmount, assetAmount - srvFee, _clientSlip);
}
function _checkWithdrawLimit(address _asset, uint256 _curPrice) internal view {
uint256 lastBalance = _getAssetBalance(_asset);
if (lastBalance != 0 && ((lastBalance * _curPrice) / _getUnitSize(_asset)) < 1 ether) {
revert E_WithdrawLimit();
}
}
function _checkAmountSlip(uint256 _eAmount, uint256 _rAmount, uint16 _clientSlip) internal pure {
if (_clientSlip > _slip) revert E_SlipLimit();
if ((_eAmount * (_perMil - _clientSlip)) / _perMil > _rAmount) {
revert E_Expected();
}
}
function rebaseCToken() external nonReentrant {
if (block.timestamp > _pool.endTime || _pool.endPrice > 0) revert E_PoolEnd();
_rebaseCToken();
}
function _rebaseCToken() internal {
uint256 avg = _getAssetAvg(_pool.asset);
uint256 curPrice = _getCurPrice(_pool.asset);
if (avg == 0 || curPrice <= avg || block.timestamp - _pool.cLastRbTime <= 1 days) {
if (avg == 0) _pool.cLastRbTime = block.timestamp;
return;
}
IDoublerFactory(_factory).mintReward(_pool.asset, _pool.id, msg.sender, 1000 ether);
_pool.cLastRbTime = block.timestamp;
uint256 cTokenTotal = IERC20(_pool.cToken).totalSupply();
uint256 rbAmount = (cTokenTotal * (curPrice - avg)) / avg / 100;
_pool.lastDayRate = (rbAmount * _perMil * _perMil) / cTokenTotal;
cTokenTotal = cTokenTotal + rbAmount;
IRBToken(_pool.cToken).rebase(cTokenTotal);
}
function endPool() external nonReentrant returns (bool) {
if (block.timestamp <= _pool.endTime || _pool.endPrice > 0) revert E_PoolEnd();
_pool.endTime = block.timestamp;
_pool.endPrice = _getCurPrice(_pool.asset);
IDoublerFactory(_factory).mintReward(_pool.asset, _pool.id, msg.sender, 10000 ether);
emit EndPool(_pool.asset, _pool.id, block.timestamp, _pool.endPrice);
return true;
}
}
文件 3 的 12:IDoubler.sol
pragma solidity ^0.8.20;
interface IDoubler {
error E_Asset();
error E_Disable();
error E_PoolEnd();
error E_FeeLimit();
error E_ZeroAddr();
error E_Balance();
error E_InputLimit();
error E_Expected();
error E_SlipLimit();
error E_BlockOnce();
error E_WithdrawLimit();
error E_EndTime();
error E_PriceLimit();
error E_Ownable();
struct Pool {
bool isNative;
uint16 inputFee;
uint16 withdrawFee;
uint256 id;
uint256 lastPrice;
uint256 cLastRbTime;
uint256 lowerOfInputMaximum;
uint256 endPrice;
uint256 startTime;
uint256 lastDayRate;
uint256 endTime;
address asset;
address cToken;
address bToken;
address creator;
}
struct MPool {
uint16 inputFee;
uint16 withdrawFee;
uint256 endTime;
address creator;
}
struct WithdrawParam {
address asset;
uint256 cAmount;
uint256 qAmount;
uint16 clientSlip;
}
event Input(
address indexed asset,
uint256 indexed poolId,
address to,
uint256 qAmount,
uint256 bAmount,
uint256 cAmount,
uint256 extBAmount
);
event Withdraw(
address indexed asset,
uint256 indexed poolId,
address to,
uint256 cAmount,
uint256 bAmount,
uint256 assetAmount
);
event UpdatePool(address indexed asset, address creator, uint16 inputFee, uint16 withdrawFee, uint256 endTime);
event UpdateLowerOfInputMaximum(uint256 oldInputLowerOfMaximum, uint256 newInputLowerOfMaximum);
event EndPool(address asset, uint256 poolId, uint256 endTime, uint256 endPrice);
event PoolStream(
address asset,
uint256 poolId,
uint256 qAmount,
uint256 bTotal,
uint256 cTotal,
uint256 curPrice,
uint256 avg
);
function getUserExtraBToken(address _to) external view returns(uint256);
function updatePool(MPool calldata _updatePool) external;
function inputEth(uint256 _qAmount, address _to) external payable;
function input(uint256 _qAmount, address _to) external;
function withdraw(uint256 _cAmount, uint256 _qAmount, uint16 _clientSlip) external;
function claim() external;
function getPool() external view returns (Pool memory pool);
function rebaseCToken() external;
function endPool() external returns (bool);
}
文件 4 的 12:IDoublerFactory.sol
pragma solidity ^0.8.20;
interface IDoublerFactory {
error E_Minter();
error E_Initialized();
error E_ZeroAddr();
error E_EndTime();
error E_PoolId();
struct AddPool {
uint16 inputFee;
uint16 withdrawFee;
uint256 lowerOfInputMaximum;
address asset;
uint256 poolId;
uint256 startTime;
uint256 endTime;
address creator;
string namePre;
string symbolPre;
}
event NewPool(address indexed asset, uint256 poolId, address pool, address cToken, address bToken);
event MintReward(address _asset, uint256 _poolId, address _to, uint256 _amount);
event UpdateEcoAddr(address ecoAddr, address newEcoAddr);
function newPool(AddPool calldata _addPool) external;
function mintReward(address _asset, uint256 _poolId, address _to, uint256 _amount) external;
function getFastPriceFeed() external view returns (address);
function getFactoryOwner() external view returns (address);
function getWethAddr() external view returns (address);
function getEcoAddr() external view returns (address);
function getLatestPoolId(address _asset) external view returns (uint256);
function getPoolAddr(address _asset, uint256 _poolId) external view returns (address);
function getRewardAddr() external view returns (address);
}
文件 5 的 12:IERC20.sol
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 6 的 12:IERC20Metadata.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 7 的 12:IERC20Permit.sol
pragma solidity ^0.8.20;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 8 的 12:IFastPriceFeed.sol
pragma solidity ^0.8.20;
interface IFastPriceFeed {
error E_PriceLimits();
error E_ZeroAddr();
error E_AssetSupported();
error E_AssetExist();
error E_PlanExist();
error E_Switch();
error E_PlanNotExist();
error E_TimeLimit();
error E_PriceRange();
error E_InitOracle();
error E_TwapInterval();
enum Plan {
DEX,
CHAINLINK
}
struct PriceFeed {
Plan plan;
address oracleAddr;
uint32 timeLimit;
uint256 priceMin;
uint256 priceMax;
}
event SetAssetTimeLimit(address asset, uint256 oldTimeLimit, uint256 newTimeLimit);
event SetPriceLimit(address indexed asset, Plan plan, uint256 priceMin, uint256 priceMax);
event SetPriceFee(
address indexed asset,
Plan plan,
address oracleAddr,
uint256 timeLimit,
uint256 priceMin,
uint256 priceMax
);
function getPrice(address _asset) external view returns (uint256 price);
function getAssetPlan(address _asset) external view returns (Plan);
function getPriceFeeds(address _asset, Plan _plan) external view returns (PriceFeed memory);
}
文件 9 的 12:IRBToken.sol
pragma solidity ^0.8.20;
import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
interface IRBToken is IERC20Metadata {
error E_ZeroAddr();
error E_Rebase();
error E_AllowanceInvalid();
error E_TransferRBContract();
error E_BalanceInvalid();
error E_AmountInvalid();
event TransferShares(address indexed from, address indexed to, uint256 sharesValue);
event SharesBurnt(
address indexed account,
uint256 preRebaseTokenAmount,
uint256 postRebaseTokenAmount,
uint256 sharesAmount
);
event Rebase(address asset, uint256 originTotalSupply, uint256 newTotalSupply);
function mint(address _recipient, uint256 _tokenAmount) external;
function mintWithFee(
address _recipient,
uint256 _tokenAmount,
address[] memory _srvFeeAddr,
uint16 _srvFeeRatio
) external returns (uint256 recipientTokenAmount);
function burnFrom(address _from, uint256 _tokenAmount) external;
function rebase(uint256 _newTotalSupply) external;
function totalShare() external view returns (uint256);
function sharesOf(address _account) external view returns (uint256);
function transferShares(address _recipient, uint256 _sharesAmount) external returns (uint256);
function transferSharesFrom(address _sender, address _recipient, uint256 _sharesAmount) external returns (uint256);
}
文件 10 的 12:IWETH.sol
pragma solidity ^0.8.20;
interface IWETH {
function deposit() external payable;
}
文件 11 的 12:ReentrancyGuard.sol
pragma solidity ^0.8.20;
abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
_status = ENTERED;
}
function _nonReentrantAfter() private {
_status = NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
文件 12 的 12:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}
{
"compilationTarget": {
"contracts/Doubler.sol": "Doubler"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_initParent","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"E_Asset","type":"error"},{"inputs":[],"name":"E_Balance","type":"error"},{"inputs":[],"name":"E_BlockOnce","type":"error"},{"inputs":[],"name":"E_Disable","type":"error"},{"inputs":[],"name":"E_EndTime","type":"error"},{"inputs":[],"name":"E_Expected","type":"error"},{"inputs":[],"name":"E_FeeLimit","type":"error"},{"inputs":[],"name":"E_InputLimit","type":"error"},{"inputs":[],"name":"E_Ownable","type":"error"},{"inputs":[],"name":"E_PoolEnd","type":"error"},{"inputs":[],"name":"E_PriceLimit","type":"error"},{"inputs":[],"name":"E_SlipLimit","type":"error"},{"inputs":[],"name":"E_WithdrawLimit","type":"error"},{"inputs":[],"name":"E_ZeroAddr","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endPrice","type":"uint256"}],"name":"EndPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"qAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"extBAmount","type":"uint256"}],"name":"Input","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"qAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bTotal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cTotal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"curPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"avg","type":"uint256"}],"name":"PoolStream","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldInputLowerOfMaximum","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newInputLowerOfMaximum","type":"uint256"}],"name":"UpdateLowerOfInputMaximum","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"uint16","name":"inputFee","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"withdrawFee","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"UpdatePool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"cAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getPool","outputs":[{"components":[{"internalType":"bool","name":"isNative","type":"bool"},{"internalType":"uint16","name":"inputFee","type":"uint16"},{"internalType":"uint16","name":"withdrawFee","type":"uint16"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"lastPrice","type":"uint256"},{"internalType":"uint256","name":"cLastRbTime","type":"uint256"},{"internalType":"uint256","name":"lowerOfInputMaximum","type":"uint256"},{"internalType":"uint256","name":"endPrice","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"lastDayRate","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"bToken","type":"address"},{"internalType":"address","name":"creator","type":"address"}],"internalType":"struct IDoubler.Pool","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"getUserExtraBToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_initFastPriceFeed","type":"address"},{"components":[{"internalType":"bool","name":"isNative","type":"bool"},{"internalType":"uint16","name":"inputFee","type":"uint16"},{"internalType":"uint16","name":"withdrawFee","type":"uint16"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"lastPrice","type":"uint256"},{"internalType":"uint256","name":"cLastRbTime","type":"uint256"},{"internalType":"uint256","name":"lowerOfInputMaximum","type":"uint256"},{"internalType":"uint256","name":"endPrice","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"lastDayRate","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"bToken","type":"address"},{"internalType":"address","name":"creator","type":"address"}],"internalType":"struct IDoubler.Pool","name":"_initPool","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_qAmount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"input","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_qAmount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"inputEth","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"rebaseCToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"inputFee","type":"uint16"},{"internalType":"uint16","name":"withdrawFee","type":"uint16"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"address","name":"creator","type":"address"}],"internalType":"struct IDoubler.MPool","name":"_updatePl","type":"tuple"}],"name":"updatePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_cAmount","type":"uint256"},{"internalType":"uint256","name":"_qAmount","type":"uint256"},{"internalType":"uint16","name":"_clientSlip","type":"uint16"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]