Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x61010060 | 22352769 | 320 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x802187Cd...f623af4AF The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
RateKeeperFactory
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 1000 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {IRateKeeper} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IRateKeeper.sol";
import {IGaugeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IGaugeV3.sol";
import {IFactory} from "../interfaces/factories/IFactory.sol";
import {IMarketFactory} from "../interfaces/factories/IMarketFactory.sol";
import {IRateKeeperFactory} from "../interfaces/factories/IRateKeeperFactory.sol";
import {Call, DeployParams, DeployResult} from "../interfaces/Types.sol";
import {CallBuilder} from "../libraries/CallBuilder.sol";
import {
DOMAIN_RATE_KEEPER,
AP_RATE_KEEPER_FACTORY,
NO_VERSION_CONTROL,
AP_GEAR_STAKING
} from "../libraries/ContractLiterals.sol";
import {AbstractFactory} from "./AbstractFactory.sol";
import {AbstractMarketFactory} from "./AbstractMarketFactory.sol";
contract RateKeeperFactory is AbstractMarketFactory, IRateKeeperFactory {
using CallBuilder for Call[];
uint256 public constant override version = 3_10;
bytes32 public constant override contractType = AP_RATE_KEEPER_FACTORY;
address public immutable gearStaking;
constructor(address addressProvider_) AbstractFactory(addressProvider_) {
gearStaking = _getAddressOrRevert(AP_GEAR_STAKING, NO_VERSION_CONTROL);
}
// ---------- //
// DEPLOYMENT //
// ---------- //
function deployRateKeeper(address pool, DeployParams calldata params)
external
override
onlyMarketConfigurators
returns (DeployResult memory)
{
if (params.postfix == "GAUGE") {
(address decodedPool, address decodedGearStaking) = abi.decode(params.constructorParams, (address, address));
if (decodedPool != pool || decodedGearStaking != gearStaking) revert InvalidConstructorParamsException();
} else if (params.postfix == "TUMBLER") {
(address decodedPool,) = abi.decode(params.constructorParams, (address, uint256));
if (decodedPool != pool) revert InvalidConstructorParamsException();
} else {
_validateDefaultConstructorParams(pool, params.constructorParams);
}
address rateKeeper = _deployLatestPatch({
contractType: _getContractType(DOMAIN_RATE_KEEPER, params.postfix),
minorVersion: version,
constructorParams: params.constructorParams,
salt: keccak256(abi.encode(params.salt, msg.sender))
});
return DeployResult({
newContract: rateKeeper,
onInstallOps: CallBuilder.build(_authorizeFactory(msg.sender, pool, rateKeeper))
});
}
// ------------ //
// MARKET HOOKS //
// ------------ //
function onCreateMarket(address, address, address, address rateKeeper, address, address)
external
view
override(AbstractMarketFactory, IMarketFactory)
returns (Call[] memory)
{
if (_getRateKeeperType(rateKeeper) == "RATE_KEEPER::GAUGE") {
return CallBuilder.build(_setFrozenEpoch(rateKeeper, false));
}
return CallBuilder.build();
}
function onShutdownMarket(address pool)
external
view
override(AbstractMarketFactory, IMarketFactory)
returns (Call[] memory)
{
address rateKeeper = _rateKeeper(_quotaKeeper(pool));
if (_getRateKeeperType(rateKeeper) == "RATE_KEEPER::GAUGE") {
return CallBuilder.build(_setFrozenEpoch(rateKeeper, true));
}
return CallBuilder.build();
}
function onUpdateRateKeeper(address pool, address newRateKeeper, address oldRateKeeper)
external
view
override(AbstractMarketFactory, IMarketFactory)
returns (Call[] memory calls)
{
address[] memory tokens = _quotedTokens(_quotaKeeper(pool));
uint256 numTokens = tokens.length;
calls = new Call[](numTokens);
bytes32 type_ = _getRateKeeperType(newRateKeeper);
for (uint256 i; i < numTokens; ++i) {
calls[i] = _addToken(newRateKeeper, tokens[i], type_);
}
if (_getRateKeeperType(oldRateKeeper) == "RATE_KEEPER::GAUGE") {
calls = calls.append(_setFrozenEpoch(oldRateKeeper, true));
}
if (type_ == "RATE_KEEPER::GAUGE") {
calls = calls.append(_setFrozenEpoch(newRateKeeper, false));
}
calls = calls.append(_unauthorizeFactory(msg.sender, pool, oldRateKeeper));
}
function onAddToken(address pool, address token, address)
external
view
override(AbstractMarketFactory, IMarketFactory)
returns (Call[] memory)
{
address rateKeeper = _rateKeeper(_quotaKeeper(pool));
return CallBuilder.build(_addToken(rateKeeper, token, _getRateKeeperType(rateKeeper)));
}
// ------------- //
// CONFIGURATION //
// ------------- //
function configure(address pool, bytes calldata callData)
external
view
override(AbstractFactory, IFactory)
returns (Call[] memory)
{
address rateKeeper = _rateKeeper(_quotaKeeper(pool));
bytes4 selector = bytes4(callData);
if (_isForbiddenConfigurationCall(rateKeeper, selector)) revert ForbiddenConfigurationCallException(selector);
return CallBuilder.build(Call(rateKeeper, callData));
}
// --------- //
// INTERNALS //
// --------- //
function _getRateKeeperType(address rateKeeper) internal view returns (bytes32) {
try IRateKeeper(rateKeeper).contractType() returns (bytes32 type_) {
return type_;
} catch {
return "RATE_KEEPER::GAUGE";
}
}
function _isForbiddenConfigurationCall(address rateKeeper, bytes4 selector) internal view returns (bool) {
if (_getRateKeeperType(rateKeeper) == "RATE_KEEPER::GAUGE") {
return selector == IRateKeeper.addToken.selector || selector == IGaugeV3.addQuotaToken.selector
|| selector == IGaugeV3.setFrozenEpoch.selector || selector == bytes4(keccak256("setController(address)"));
}
return selector == IRateKeeper.addToken.selector;
}
function _addToken(address rateKeeper, address token, bytes32 type_) internal pure returns (Call memory) {
return Call(
rateKeeper,
type_ == "RATE_KEEPER::GAUGE"
? abi.encodeCall(IGaugeV3.addQuotaToken, (token, 1, 1))
: abi.encodeCall(IRateKeeper.addToken, token)
);
}
function _setFrozenEpoch(address gauge, bool status) internal pure returns (Call memory) {
return Call(gauge, abi.encodeCall(IGaugeV3.setFrozenEpoch, status));
}
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;
import {IStateSerializer} from "./IStateSerializer.sol";
import {IVersion} from "./IVersion.sol";
/// @title Rate keeper interface
/// @notice Generic interface for a contract that can provide rates to the quota keeper
/// @dev Bots must have type `RATE_KEEPER::{POSTFIX}`
interface IRateKeeper is IVersion, IStateSerializer {
/// @notice Pool rates are provided for
function pool() external view returns (address);
/// @notice Adds token to the rate keeper
/// @dev Must add token to the quota keeper in case it's not already there
function addToken(address token) external;
/// @notice Whether token is added to the rate keeper
function isTokenAdded(address token) external view returns (bool);
/// @notice Returns quota rates for a list of tokens, must return non-zero rates for added tokens
/// and revert if some tokens are not recognized
function getRates(address[] calldata tokens) external view returns (uint16[] memory);
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;
import {IACLTrait} from "./base/IACLTrait.sol";
import {IRateKeeper} from "./base/IRateKeeper.sol";
import {IVotingContract} from "./base/IVotingContract.sol";
struct QuotaRateParams {
uint16 minRate;
uint16 maxRate;
uint96 totalVotesLpSide;
uint96 totalVotesCaSide;
}
struct UserVotes {
uint96 votesLpSide;
uint96 votesCaSide;
}
interface IGaugeV3Events {
/// @notice Emitted when epoch is updated
event UpdateEpoch(uint16 epochNow);
/// @notice Emitted when a user submits a vote
event Vote(address indexed user, address indexed token, uint96 votes, bool lpSide);
/// @notice Emitted when a user removes a vote
event Unvote(address indexed user, address indexed token, uint96 votes, bool lpSide);
/// @notice Emitted when a new quota token is added in the PoolQuotaKeeper
event AddQuotaToken(address indexed token, uint16 minRate, uint16 maxRate);
/// @notice Emitted when quota interest rate parameters are changed
event SetQuotaTokenParams(address indexed token, uint16 minRate, uint16 maxRate);
/// @notice Emitted when the frozen epoch status changes
event SetFrozenEpoch(bool status);
}
/// @title Gauge V3 interface
interface IGaugeV3 is IVotingContract, IRateKeeper, IACLTrait, IGaugeV3Events {
function updateEpoch() external;
function epochLastUpdate() external view returns (uint16);
function getRates(address[] calldata tokens) external view override returns (uint16[] memory);
function vote(address user, uint96 votes, bytes calldata extraData) external override;
function unvote(address user, uint96 votes, bytes calldata extraData) external override;
function userTokenVotes(address user, address token)
external
view
returns (uint96 votesLpSide, uint96 votesCaSide);
function quotaRateParams(address token)
external
view
returns (uint16 minRate, uint16 maxRate, uint96 totalVotesLpSide, uint96 totalVotesCaSide);
// ------------- //
// CONFIGURATION //
// ------------- //
function epochFrozen() external view returns (bool);
function setFrozenEpoch(bool status) external;
function addQuotaToken(address token, uint16 minRate, uint16 maxRate) external;
function changeQuotaMinRate(address token, uint16 minRate) external;
function changeQuotaMaxRate(address token, uint16 maxRate) external;
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol";
import {IDeployerTrait} from "../base/IDeployerTrait.sol";
import {Call} from "../Types.sol";
interface IFactory is IVersion, IDeployerTrait {
// ------ //
// ERRORS //
// ------ //
error CallerIsNotMarketConfiguratorException(address caller);
error ForbiddenConfigurationCallException(bytes4 selector);
error ForbiddenEmergencyConfigurationCallException(bytes4 selector);
error InvalidConstructorParamsException();
// --------------- //
// STATE VARIABLES //
// --------------- //
function marketConfiguratorFactory() external view returns (address);
// ------------- //
// CONFIGURATION //
// ------------- //
function configure(address target, bytes calldata callData) external returns (Call[] memory calls);
function emergencyConfigure(address target, bytes calldata callData) external returns (Call[] memory calls);
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {Call} from "../Types.sol";
import {IFactory} from "./IFactory.sol";
interface IMarketFactory is IFactory {
// ------------ //
// MARKET HOOKS //
// ------------ //
function onCreateMarket(
address pool,
address priceOracle,
address interestRateModel,
address rateKeeper,
address lossPolicy,
address underlyingPriceFeed
) external returns (Call[] memory calls);
function onShutdownMarket(address pool) external returns (Call[] memory calls);
function onCreateCreditSuite(address creditManager) external returns (Call[] memory calls);
function onShutdownCreditSuite(address creditManager) external returns (Call[] memory calls);
function onUpdatePriceOracle(address pool, address newPriceOracle, address oldPriceOracle)
external
returns (Call[] memory calls);
function onUpdateInterestRateModel(address pool, address newInterestRateModel, address oldInterestRateModel)
external
returns (Call[] memory calls);
function onUpdateRateKeeper(address pool, address newRateKeeper, address oldRateKeeper)
external
returns (Call[] memory calls);
function onUpdateLossPolicy(address pool, address newLossPolicy, address oldLossPolicy)
external
returns (Call[] memory calls);
function onAddToken(address pool, address token, address priceFeed) external returns (Call[] memory calls);
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {DeployParams, DeployResult} from "../Types.sol";
import {IMarketFactory} from "./IMarketFactory.sol";
interface IRateKeeperFactory is IMarketFactory {
function deployRateKeeper(address pool, DeployParams calldata params) external returns (DeployResult memory);
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
struct AddressProviderEntry {
bytes32 key;
uint256 ver;
address value;
}
struct AuditReport {
address auditor;
string reportUrl;
bytes signature;
}
struct Bytecode {
bytes32 contractType;
uint256 version;
bytes initCode;
address author;
string source;
bytes authorSignature;
}
struct BytecodePointer {
bytes32 contractType;
uint256 version;
address initCodePointer;
address author;
string source;
bytes authorSignature;
}
struct Call {
address target;
bytes callData;
}
struct ConnectedPriceFeed {
address token;
address[] priceFeeds;
}
struct CrossChainCall {
uint256 chainId; // 0 means to be executed on all chains
address target;
bytes callData;
}
struct DeployParams {
bytes32 postfix;
bytes32 salt;
bytes constructorParams;
}
struct DeployResult {
address newContract;
Call[] onInstallOps;
}
struct MarketFactories {
address poolFactory;
address priceOracleFactory;
address interestRateModelFactory;
address rateKeeperFactory;
address lossPolicyFactory;
}
struct PriceFeedInfo {
string name;
uint32 stalenessPeriod;
bytes32 priceFeedType;
uint256 version;
}
struct SignedBatch {
string name;
bytes32 prevHash;
CrossChainCall[] calls;
bytes[] signatures;
}
struct SignedRecoveryModeMessage {
uint256 chainId;
bytes32 startingBatchHash;
bytes[] signatures;
}
struct Split {
bool initialized;
address[] receivers;
uint16[] proportions;
}
struct TwoAdminProposal {
bytes callData;
bool confirmedByAdmin;
bool confirmedByTreasuryProxy;
}// SPDX-License-Identifier: BUSL-1.1
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {Call} from "../interfaces/Types.sol";
library CallBuilder {
function build() internal pure returns (Call[] memory calls) {}
function build(Call memory call1) internal pure returns (Call[] memory calls) {
calls = new Call[](1);
calls[0] = call1;
}
function build(Call memory call1, Call memory call2) internal pure returns (Call[] memory calls) {
calls = new Call[](2);
calls[0] = call1;
calls[1] = call2;
}
function build(Call memory call1, Call memory call2, Call memory call3)
internal
pure
returns (Call[] memory calls)
{
calls = new Call[](3);
calls[0] = call1;
calls[1] = call2;
calls[2] = call3;
}
function build(Call memory call1, Call memory call2, Call memory call3, Call memory call4)
internal
pure
returns (Call[] memory calls)
{
calls = new Call[](4);
calls[0] = call1;
calls[1] = call2;
calls[2] = call3;
calls[3] = call4;
}
function build(Call memory call1, Call memory call2, Call memory call3, Call memory call4, Call memory call5)
internal
pure
returns (Call[] memory calls)
{
calls = new Call[](5);
calls[0] = call1;
calls[1] = call2;
calls[2] = call3;
calls[3] = call4;
calls[4] = call5;
}
function build(
Call memory call1,
Call memory call2,
Call memory call3,
Call memory call4,
Call memory call5,
Call memory call6
) internal pure returns (Call[] memory calls) {
calls = new Call[](6);
calls[0] = call1;
calls[1] = call2;
calls[2] = call3;
calls[3] = call4;
calls[4] = call5;
calls[5] = call6;
}
function append(Call[] memory calls, Call memory call) internal pure returns (Call[] memory newCalls) {
uint256 numCalls = calls.length;
newCalls = new Call[](numCalls + 1);
for (uint256 i; i < numCalls; ++i) {
newCalls[i] = calls[i];
}
newCalls[numCalls] = call;
}
function extend(Call[] memory calls1, Call[] memory calls2) internal pure returns (Call[] memory newCalls) {
uint256 num1 = calls1.length;
uint256 num2 = calls2.length;
newCalls = new Call[](num1 + num2);
for (uint256 i; i < num1; ++i) {
newCalls[i] = calls1[i];
}
for (uint256 i; i < num2; ++i) {
newCalls[num1 + i] = calls2[i];
}
}
}// SPDX-License-Identifier: BUSL-1.1 // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024. pragma solidity ^0.8.23; uint256 constant NO_VERSION_CONTROL = 0; // Contract types and prefixes bytes32 constant AP_ACCOUNT_FACTORY_DEFAULT = "ACCOUNT_FACTORY::DEFAULT"; bytes32 constant AP_ACL = "ACL"; bytes32 constant AP_ADDRESS_PROVIDER = "ADDRESS_PROVIDER"; bytes32 constant AP_BOT_LIST = "BOT_LIST"; bytes32 constant AP_BYTECODE_REPOSITORY = "BYTECODE_REPOSITORY"; bytes32 constant AP_CONTRACTS_REGISTER = "CONTRACTS_REGISTER"; bytes32 constant AP_CREDIT_CONFIGURATOR = "CREDIT_CONFIGURATOR"; bytes32 constant AP_CREDIT_FACADE = "CREDIT_FACADE"; bytes32 constant AP_CREDIT_FACTORY = "CREDIT_FACTORY"; bytes32 constant AP_CREDIT_MANAGER = "CREDIT_MANAGER"; bytes32 constant AP_CROSS_CHAIN_GOVERNANCE = "CROSS_CHAIN_GOVERNANCE"; bytes32 constant AP_CROSS_CHAIN_GOVERNANCE_PROXY = "CROSS_CHAIN_GOVERNANCE_PROXY"; bytes32 constant AP_CROSS_CHAIN_MULTISIG = "CROSS_CHAIN_MULTISIG"; bytes32 constant AP_GEAR_STAKING = "GEAR_STAKING"; bytes32 constant AP_GEAR_TOKEN = "GEAR_TOKEN"; bytes32 constant AP_GOVERNOR = "GOVERNOR"; bytes32 constant AP_INSTANCE_MANAGER = "INSTANCE_MANAGER"; bytes32 constant AP_INSTANCE_MANAGER_PROXY = "INSTANCE_MANAGER_PROXY"; bytes32 constant AP_INTEREST_RATE_MODEL_DEFAULT = "IRM::DEFAULT"; bytes32 constant AP_INTEREST_RATE_MODEL_FACTORY = "INTEREST_RATE_MODEL_FACTORY"; bytes32 constant AP_INTEREST_RATE_MODEL_LINEAR = "IRM::LINEAR"; bytes32 constant AP_LOSS_POLICY_ALIASED = "LOSS_POLICY::ALIASED"; bytes32 constant AP_LOSS_POLICY_DEFAULT = "LOSS_POLICY::DEFAULT"; bytes32 constant AP_LOSS_POLICY_FACTORY = "LOSS_POLICY_FACTORY"; bytes32 constant AP_MARKET_CONFIGURATOR = "MARKET_CONFIGURATOR"; bytes32 constant AP_MARKET_CONFIGURATOR_FACTORY = "MARKET_CONFIGURATOR_FACTORY"; bytes32 constant AP_MARKET_CONFIGURATOR_LEGACY = "MARKET_CONFIGURATOR::LEGACY"; bytes32 constant AP_POOL = "POOL"; bytes32 constant AP_POOL_FACTORY = "POOL_FACTORY"; bytes32 constant AP_POOL_QUOTA_KEEPER = "POOL_QUOTA_KEEPER"; bytes32 constant AP_PRICE_FEED_STORE = "PRICE_FEED_STORE"; bytes32 constant AP_PRICE_ORACLE = "PRICE_ORACLE"; bytes32 constant AP_PRICE_ORACLE_FACTORY = "PRICE_ORACLE_FACTORY"; bytes32 constant AP_RATE_KEEPER_FACTORY = "RATE_KEEPER_FACTORY"; bytes32 constant AP_RATE_KEEPER_GAUGE = "RATE_KEEPER::GAUGE"; bytes32 constant AP_RATE_KEEPER_TUMBLER = "RATE_KEEPER::TUMBLER"; bytes32 constant AP_TREASURY = "TREASURY"; bytes32 constant AP_TREASURY_PROXY = "TREASURY_PROXY"; bytes32 constant AP_TREASURY_SPLITTER = "TREASURY_SPLITTER"; bytes32 constant AP_WETH_TOKEN = "WETH_TOKEN"; bytes32 constant AP_ZERO_PRICE_FEED = "PRICE_FEED::ZERO"; // Common domains bytes32 constant DOMAIN_ACCOUNT_FACTORY = "ACCOUNT_FACTORY"; bytes32 constant DOMAIN_ADAPTER = "ADAPTER"; bytes32 constant DOMAIN_BOT = "BOT"; bytes32 constant DOMAIN_CREDIT_MANAGER = "CREDIT_MANAGER"; bytes32 constant DOMAIN_DEGEN_NFT = "DEGEN_NFT"; bytes32 constant DOMAIN_IRM = "IRM"; bytes32 constant DOMAIN_LOSS_POLICY = "LOSS_POLICY"; bytes32 constant DOMAIN_POOL = "POOL"; bytes32 constant DOMAIN_PRICE_FEED = "PRICE_FEED"; bytes32 constant DOMAIN_RATE_KEEPER = "RATE_KEEPER"; bytes32 constant DOMAIN_ZAPPER = "ZAPPER"; // Roles bytes32 constant ROLE_EMERGENCY_LIQUIDATOR = "EMERGENCY_LIQUIDATOR"; bytes32 constant ROLE_PAUSABLE_ADMIN = "PAUSABLE_ADMIN"; bytes32 constant ROLE_UNPAUSABLE_ADMIN = "UNPAUSABLE_ADMIN";
// SPDX-License-Identifier: BUSL-1.1
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {IFactory} from "../interfaces/factories/IFactory.sol";
import {IMarketConfigurator} from "../interfaces/IMarketConfigurator.sol";
import {IMarketConfiguratorFactory} from "../interfaces/IMarketConfiguratorFactory.sol";
import {Call} from "../interfaces/Types.sol";
import {AP_MARKET_CONFIGURATOR_FACTORY, NO_VERSION_CONTROL} from "../libraries/ContractLiterals.sol";
import {DeployerTrait} from "../traits/DeployerTrait.sol";
abstract contract AbstractFactory is DeployerTrait, IFactory {
address public immutable override marketConfiguratorFactory;
modifier onlyMarketConfigurators() {
_ensureCallerIsMarketConfigurator();
_;
}
constructor(address addressProvider_) DeployerTrait(addressProvider_) {
marketConfiguratorFactory = _getAddressOrRevert(AP_MARKET_CONFIGURATOR_FACTORY, NO_VERSION_CONTROL);
}
// ------------- //
// CONFIGURATION //
// ------------- //
function configure(address, bytes calldata callData) external virtual override returns (Call[] memory) {
revert ForbiddenConfigurationCallException(bytes4(callData));
}
function emergencyConfigure(address, bytes calldata callData) external virtual override returns (Call[] memory) {
revert ForbiddenEmergencyConfigurationCallException(bytes4(callData));
}
// --------- //
// INTERNALS //
// --------- //
function _ensureCallerIsMarketConfigurator() internal view {
if (!IMarketConfiguratorFactory(marketConfiguratorFactory).isMarketConfigurator(msg.sender)) {
revert CallerIsNotMarketConfiguratorException(msg.sender);
}
}
function _authorizeFactory(address marketConfigurator, address suite, address target)
internal
view
returns (Call memory)
{
return Call({
target: marketConfigurator,
callData: abi.encodeCall(IMarketConfigurator.authorizeFactory, (address(this), suite, target))
});
}
function _unauthorizeFactory(address marketConfigurator, address suite, address target)
internal
view
returns (Call memory)
{
return Call({
target: marketConfigurator,
callData: abi.encodeCall(IMarketConfigurator.unauthorizeFactory, (address(this), suite, target))
});
}
}// SPDX-License-Identifier: BUSL-1.1
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IPoolQuotaKeeperV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IPoolQuotaKeeperV3.sol";
import {IPoolV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IPoolV3.sol";
import {IMarketFactory} from "../interfaces/factories/IMarketFactory.sol";
import {IContractsRegister} from "../interfaces/IContractsRegister.sol";
import {IMarketConfigurator} from "../interfaces/IMarketConfigurator.sol";
import {Call} from "../interfaces/Types.sol";
import {AbstractFactory} from "./AbstractFactory.sol";
abstract contract AbstractMarketFactory is AbstractFactory, IMarketFactory {
// ------------ //
// MARKET HOOKS //
// ------------ //
function onCreateMarket(address, address, address, address, address, address)
external
virtual
override
returns (Call[] memory)
{}
function onShutdownMarket(address) external virtual override returns (Call[] memory) {}
function onCreateCreditSuite(address) external virtual override returns (Call[] memory) {}
function onShutdownCreditSuite(address) external virtual override returns (Call[] memory) {}
function onUpdatePriceOracle(address, address, address) external virtual override returns (Call[] memory) {}
function onUpdateInterestRateModel(address, address, address) external virtual override returns (Call[] memory) {}
function onUpdateRateKeeper(address, address, address) external virtual override returns (Call[] memory) {}
function onUpdateLossPolicy(address, address, address) external virtual override returns (Call[] memory) {}
function onAddToken(address, address, address) external virtual override returns (Call[] memory) {}
// --------- //
// INTERNALS //
// --------- //
function _validateDefaultConstructorParams(address pool, bytes calldata constructorParams) internal view {
(address decodedPool, address decodedAddressProvider) = abi.decode(constructorParams[:64], (address, address));
if (decodedPool != pool || decodedAddressProvider != addressProvider) {
revert InvalidConstructorParamsException();
}
}
function _marketConfigurator(address pool) internal view returns (address) {
return Ownable(IPoolV3(pool).acl()).owner();
}
function _contractsRegister(address pool) internal view returns (address) {
return IMarketConfigurator(_marketConfigurator(pool)).contractsRegister();
}
function _underlying(address pool) internal view returns (address) {
return IPoolV3(pool).asset();
}
function _quotaKeeper(address pool) internal view returns (address) {
return IPoolV3(pool).poolQuotaKeeper();
}
function _interestRateModel(address pool) internal view returns (address) {
return IPoolV3(pool).interestRateModel();
}
function _priceOracle(address pool) internal view returns (address) {
return IContractsRegister(_contractsRegister(pool)).getPriceOracle(pool);
}
function _lossPolicy(address pool) internal view returns (address) {
return IContractsRegister(_contractsRegister(pool)).getLossPolicy(pool);
}
function _rateKeeper(address quotaKeeper) internal view returns (address) {
return IPoolQuotaKeeperV3(quotaKeeper).gauge();
}
function _quotedTokens(address quotaKeeper) internal view returns (address[] memory) {
return IPoolQuotaKeeperV3(quotaKeeper).quotedTokens();
}
function _isQuotedToken(address quotaKeeper, address token) internal view returns (bool) {
return IPoolQuotaKeeperV3(quotaKeeper).isQuotedToken(token);
}
function _quota(address quotaKeeper, address token) internal view returns (uint96 quota) {
(,,, quota,,) = IPoolQuotaKeeperV3(quotaKeeper).getTokenQuotaParams(token);
}
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;
/// @title State serializer interface
/// @notice Generic interface for a contract that can serialize its state into a bytes array
interface IStateSerializer {
/// @notice Serializes the state of the contract into a bytes array `serializedData`
function serialize() external view returns (bytes memory serializedData);
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;
/// @title Version interface
/// @notice Defines contract version and type
interface IVersion {
/// @notice Contract version
function version() external view returns (uint256);
/// @notice Contract type
function contractType() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;
interface IACLTrait {
function acl() external view returns (address);
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;
/// @title Voting contract interface
/// @notice Generic interface for a contract that can be voted for in `GearStakingV3` contract
/// @dev `vote` and `unvote` must implement votes accounting since it's not performed on the staking contract side
interface IVotingContract {
function voter() external view returns (address);
function vote(address user, uint96 votes, bytes calldata extraData) external;
function unvote(address user, uint96 votes, bytes calldata extraData) external;
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
/// @title Deployer trait interface
interface IDeployerTrait {
function addressProvider() external view returns (address);
function bytecodeRepository() external view returns (address);
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol";
import {IDeployerTrait} from "./base/IDeployerTrait.sol";
import {Call, DeployParams, MarketFactories} from "./Types.sol";
interface IMarketConfigurator is IVersion, IDeployerTrait {
// ------ //
// EVENTS //
// ------ //
event SetEmergencyAdmin(address indexed newEmergencyAdmin);
event GrantRole(bytes32 indexed role, address indexed account);
event RevokeRole(bytes32 indexed role, address indexed account);
event EmergencyRevokeRole(bytes32 indexed role, address indexed account);
event CreateMarket(
address indexed pool,
address priceOracle,
address interestRateModel,
address rateKeeper,
address lossPolicy,
MarketFactories factories
);
event ShutdownMarket(address indexed pool);
event AddToken(address indexed pool, address indexed token);
event ConfigurePool(address indexed pool, bytes data);
event EmergencyConfigurePool(address indexed pool, bytes data);
event CreateCreditSuite(address indexed creditManager, address factory);
event ShutdownCreditSuite(address indexed creditManager);
event ConfigureCreditSuite(address indexed creditManager, bytes data);
event EmergencyConfigureCreditSuite(address indexed creditManager, bytes data);
event UpdatePriceOracle(address indexed pool, address priceOracle);
event ConfigurePriceOracle(address indexed pool, bytes data);
event EmergencyConfigurePriceOracle(address indexed pool, bytes data);
event UpdateInterestRateModel(address indexed pool, address interestRateModel);
event ConfigureInterestRateModel(address indexed pool, bytes data);
event EmergencyConfigureInterestRateModel(address indexed pool, bytes data);
event UpdateRateKeeper(address indexed pool, address rateKeeper);
event ConfigureRateKeeper(address indexed pool, bytes data);
event EmergencyConfigureRateKeeper(address indexed pool, bytes data);
event UpdateLossPolicy(address indexed pool, address lossPolicy);
event ConfigureLossPolicy(address indexed pool, bytes data);
event EmergencyConfigureLossPolicy(address indexed pool, bytes data);
event AddPeripheryContract(bytes32 indexed domain, address indexed peripheryContract);
event RemovePeripheryContract(bytes32 indexed domain, address indexed peripheryContract);
event AuthorizeFactory(address indexed factory, address indexed suite, address indexed target);
event UnauthorizeFactory(address indexed factory, address indexed suite, address indexed target);
event UpgradePoolFactory(address indexed pool, address factory);
event UpgradePriceOracleFactory(address indexed pool, address factory);
event UpgradeInterestRateModelFactory(address indexed pool, address factory);
event UpgradeRateKeeperFactory(address indexed pool, address factory);
event UpgradeLossPolicyFactory(address indexed pool, address factory);
event UpgradeCreditFactory(address indexed creditManager, address factory);
event ExecuteHook(address indexed target, bytes callData);
// ------ //
// ERRORS //
// ------ //
error CallerIsNotAdminException(address caller);
error CallerIsNotEmergencyAdminException(address caller);
error CallerIsNotSelfException(address caller);
error CreditSuiteNotRegisteredException(address creditManager);
error IncorrectMinorVersionException(uint256 version);
error IncorrectPeripheryContractException(address peripheryContract);
error MarketNotRegisteredException(address pool);
error UnauthorizedFactoryException(address factory, address target);
// --------------- //
// STATE VARIABLES //
// --------------- //
function admin() external view returns (address);
function emergencyAdmin() external view returns (address);
function curatorName() external view returns (string memory);
function acl() external view returns (address);
function contractsRegister() external view returns (address);
function treasury() external view returns (address);
// ---------------- //
// ROLES MANAGEMENT //
// ---------------- //
function setEmergencyAdmin(address newEmergencyAdmin) external;
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function emergencyRevokeRole(bytes32 role, address account) external;
// ----------------- //
// MARKET MANAGEMENT //
// ----------------- //
function previewCreateMarket(uint256 minorVersion, address underlying, string calldata name, string calldata symbol)
external
view
returns (address pool);
function createMarket(
uint256 minorVersion,
address underlying,
string calldata name,
string calldata symbol,
DeployParams calldata interestRateModelParams,
DeployParams calldata rateKeeperParams,
DeployParams calldata lossPolicyParams,
address underlyingPriceFeed
) external returns (address pool);
function shutdownMarket(address pool) external;
function addToken(address pool, address token, address priceFeed) external;
function configurePool(address pool, bytes calldata data) external;
function emergencyConfigurePool(address pool, bytes calldata data) external;
// ----------------------- //
// CREDIT SUITE MANAGEMENT //
// ----------------------- //
function previewCreateCreditSuite(uint256 minorVersion, address pool, bytes calldata encodedParams)
external
view
returns (address creditManager);
function previewCreateCreditSuite(
uint256 marketMinorVersion,
uint256 creditSuiteMinorVersion,
address underlying,
string calldata name,
string calldata symbol,
bytes calldata encodedParams
) external view returns (address creditManager);
function createCreditSuite(uint256 minorVersion, address pool, bytes calldata encdodedParams)
external
returns (address creditManager);
function shutdownCreditSuite(address creditManager) external;
function configureCreditSuite(address creditManager, bytes calldata data) external;
function emergencyConfigureCreditSuite(address creditManager, bytes calldata data) external;
// ----------------------- //
// PRICE ORACLE MANAGEMENT //
// ----------------------- //
function updatePriceOracle(address pool) external returns (address priceOracle);
function configurePriceOracle(address pool, bytes calldata data) external;
function emergencyConfigurePriceOracle(address pool, bytes calldata data) external;
// -------------- //
// IRM MANAGEMENT //
// -------------- //
function updateInterestRateModel(address pool, DeployParams calldata params) external returns (address irm);
function configureInterestRateModel(address pool, bytes calldata data) external;
function emergencyConfigureInterestRateModel(address pool, bytes calldata data) external;
// ---------------------- //
// RATE KEEPER MANAGEMENT //
// ---------------------- //
function updateRateKeeper(address pool, DeployParams calldata params) external returns (address rateKeeper);
function configureRateKeeper(address pool, bytes calldata data) external;
function emergencyConfigureRateKeeper(address pool, bytes calldata data) external;
// -–-------------------- //
// LOSS POLICY MANAGEMENT //
// -–-------------------- //
function updateLossPolicy(address pool, DeployParams calldata params) external returns (address lossPolicy);
function configureLossPolicy(address pool, bytes calldata data) external;
function emergencyConfigureLossPolicy(address pool, bytes calldata data) external;
// --------- //
// PERIPHERY //
// --------- //
function getPeripheryContracts(bytes32 domain) external view returns (address[] memory);
function isPeripheryContract(bytes32 domain, address peripheryContract) external view returns (bool);
function addPeripheryContract(address peripheryContract) external;
function removePeripheryContract(address peripheryContract) external;
// --------- //
// FACTORIES //
// --------- //
function getMarketFactories(address pool) external view returns (MarketFactories memory);
function getCreditFactory(address creditManager) external view returns (address);
function getAuthorizedFactory(address target) external view returns (address);
function getFactoryTargets(address factory, address suite) external view returns (address[] memory);
function authorizeFactory(address factory, address suite, address target) external;
function unauthorizeFactory(address factory, address suite, address target) external;
function upgradePoolFactory(address pool) external;
function upgradePriceOracleFactory(address pool) external;
function upgradeInterestRateModelFactory(address pool) external;
function upgradeRateKeeperFactory(address pool) external;
function upgradeLossPolicyFactory(address pool) external;
function upgradeCreditFactory(address creditManager) external;
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol";
import {IDeployerTrait} from "./base/IDeployerTrait.sol";
/// @title Market configurator factory interface
interface IMarketConfiguratorFactory is IVersion, IDeployerTrait {
// ------ //
// EVENTS //
// ------ //
event CreateMarketConfigurator(address indexed marketConfigurator, string name);
event ShutdownMarketConfigurator(address indexed marketConfigurator);
// ------ //
// ERRORS //
// ------ //
error CallerIsNotCrossChainGovernanceException(address caller);
error CallerIsNotMarketConfiguratorAdminException(address caller);
error CantShutdownMarketConfiguratorException(address marketConfigurator);
error MarketConfiguratorIsAlreadyAddedException(address marketConfigurator);
error MarketConfiguratorIsAlreadyShutdownException(address marketConfigruator);
error MarketConfiguratorIsNotRegisteredException(address marketConfigurator);
// ------- //
// GETTERS //
// ------- //
function isMarketConfigurator(address account) external view returns (bool);
function getMarketConfigurators() external view returns (address[] memory);
function getMarketConfigurator(uint256 index) external view returns (address);
function getNumMarketConfigurators() external view returns (uint256);
function getShutdownMarketConfigurators() external view returns (address[] memory);
// ------------- //
// CONFIGURATION //
// ------------- //
function createMarketConfigurator(
address emergencyAdmin,
address adminFeeTreasury,
string calldata curatorName,
bool deployGovernor
) external returns (address marketConfigurator);
function shutdownMarketConfigurator(address marketConfigurator) external;
function addMarketConfigurator(address marketConfigurator) external;
}// SPDX-License-Identifier: BUSL-1.1
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {LibString} from "@solady/utils/LibString.sol";
import {IAddressProvider} from "../interfaces/IAddressProvider.sol";
import {IBytecodeRepository} from "../interfaces/IBytecodeRepository.sol";
import {IDeployerTrait} from "../interfaces/base/IDeployerTrait.sol";
import {AP_BYTECODE_REPOSITORY, NO_VERSION_CONTROL} from "../libraries/ContractLiterals.sol";
import {Domain} from "../libraries/Domain.sol";
abstract contract DeployerTrait is IDeployerTrait {
using LibString for string;
using LibString for bytes32;
address public immutable override addressProvider;
address public immutable override bytecodeRepository;
constructor(address addressProvider_) {
addressProvider = addressProvider_;
bytecodeRepository = _getAddressOrRevert(AP_BYTECODE_REPOSITORY, NO_VERSION_CONTROL);
}
function _getAddress(bytes32 key, uint256 version) internal view returns (address) {
return IAddressProvider(addressProvider).getAddress(key, version);
}
function _getAddressOrRevert(bytes32 key, uint256 version) internal view returns (address) {
return IAddressProvider(addressProvider).getAddressOrRevert(key, version);
}
function _getContractType(bytes32 domain, bytes32 postfix) internal pure returns (bytes32) {
return Domain.getContractType(domain, postfix);
}
function _deploy(bytes32 contractType, uint256 version, bytes memory constructorParams, bytes32 salt)
internal
returns (address)
{
return IBytecodeRepository(bytecodeRepository).deploy(contractType, version, constructorParams, salt);
}
function _computeAddress(
bytes32 contractType,
uint256 version,
bytes memory constructorParams,
bytes32 salt,
address deployer
) internal view returns (address) {
return IBytecodeRepository(bytecodeRepository).computeAddress(
contractType, version, constructorParams, salt, deployer
);
}
function _deployLatestPatch(
bytes32 contractType,
uint256 minorVersion,
bytes memory constructorParams,
bytes32 salt
) internal returns (address) {
// NOTE: it's best to add a check that deployed contract's version matches the expected one in the governor
return _deploy(contractType, _getLatestPatchVersion(contractType, minorVersion), constructorParams, salt);
}
function _computeAddressLatestPatch(
bytes32 contractType,
uint256 minorVersion,
bytes memory constructorParams,
bytes32 salt,
address deployer
) internal view returns (address) {
return _computeAddress(
contractType, _getLatestPatchVersion(contractType, minorVersion), constructorParams, salt, deployer
);
}
function _getLatestPatchVersion(bytes32 contractType, uint256 minorVersion) internal view returns (uint256) {
return IBytecodeRepository(bytecodeRepository).getLatestPatchVersion(contractType, minorVersion);
}
function _getTokenSpecificPostfix(address token) internal view returns (bytes32) {
return IBytecodeRepository(bytecodeRepository).getTokenSpecificPostfix(token);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;
import {IACLTrait} from "./base/IACLTrait.sol";
import {IContractsRegisterTrait} from "./base/IContractsRegisterTrait.sol";
import {IVersion} from "./base/IVersion.sol";
struct TokenQuotaParams {
uint16 rate;
uint192 cumulativeIndexLU;
uint16 quotaIncreaseFee;
uint96 totalQuoted;
uint96 limit;
}
struct AccountQuota {
uint96 quota;
uint192 cumulativeIndexLU;
}
interface IPoolQuotaKeeperV3Events {
/// @notice Emitted when account's quota for a token is updated
event UpdateQuota(address indexed creditAccount, address indexed token, int96 quotaChange);
/// @notice Emitted when token's quota rate is updated
event UpdateTokenQuotaRate(address indexed token, uint16 rate);
/// @notice Emitted when the gauge is updated
event SetGauge(address indexed newGauge);
/// @notice Emitted when a new credit manager is allowed
event AddCreditManager(address indexed creditManager);
/// @notice Emitted when a new token is added as quoted
event AddQuotaToken(address indexed token);
/// @notice Emitted when a new total quota limit is set for a token
event SetTokenLimit(address indexed token, uint96 limit);
/// @notice Emitted when a new one-time quota increase fee is set for a token
event SetQuotaIncreaseFee(address indexed token, uint16 fee);
}
/// @title Pool quota keeper V3 interface
interface IPoolQuotaKeeperV3 is IPoolQuotaKeeperV3Events, IVersion, IACLTrait, IContractsRegisterTrait {
function pool() external view returns (address);
function underlying() external view returns (address);
// ----------------- //
// QUOTAS MANAGEMENT //
// ----------------- //
function updateQuota(address creditAccount, address token, int96 requestedChange, uint96 minQuota, uint96 maxQuota)
external
returns (uint128 caQuotaInterestChange, uint128 fees, bool enableToken, bool disableToken);
function removeQuotas(address creditAccount, address[] calldata tokens, bool setLimitsToZero) external;
function accrueQuotaInterest(address creditAccount, address[] calldata tokens) external;
function getQuotaRate(address) external view returns (uint16);
function cumulativeIndex(address token) external view returns (uint192);
function isQuotedToken(address token) external view returns (bool);
function getQuota(address creditAccount, address token)
external
view
returns (uint96 quota, uint192 cumulativeIndexLU);
function getTokenQuotaParams(address token)
external
view
returns (
uint16 rate,
uint192 cumulativeIndexLU,
uint16 quotaIncreaseFee,
uint96 totalQuoted,
uint96 limit,
bool isActive
);
function getQuotaAndOutstandingInterest(address creditAccount, address token)
external
view
returns (uint96 quoted, uint128 outstandingInterest);
function poolQuotaRevenue() external view returns (uint256);
function lastQuotaRateUpdate() external view returns (uint40);
// ------------- //
// CONFIGURATION //
// ------------- //
function gauge() external view returns (address);
function setGauge(address _gauge) external;
function creditManagers() external view returns (address[] memory);
function addCreditManager(address _creditManager) external;
function quotedTokens() external view returns (address[] memory);
function addQuotaToken(address token) external;
function updateRates() external;
function setTokenLimit(address token, uint96 limit) external;
function setTokenQuotaIncreaseFee(address token, uint16 fee) external;
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;
pragma abicoder v1;
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import {IACLTrait} from "./base/IACLTrait.sol";
import {IContractsRegisterTrait} from "./base/IContractsRegisterTrait.sol";
import {IVersion} from "./base/IVersion.sol";
interface IPoolV3Events {
/// @notice Emitted when depositing liquidity with referral code
event Refer(address indexed onBehalfOf, uint256 indexed referralCode, uint256 amount);
/// @notice Emitted when credit account borrows funds from the pool
event Borrow(address indexed creditManager, address indexed creditAccount, uint256 amount);
/// @notice Emitted when credit account's debt is repaid to the pool
event Repay(address indexed creditManager, uint256 borrowedAmount, uint256 profit, uint256 loss);
/// @notice Emitted when incurred loss can't be fully covered by burning treasury's shares
event IncurUncoveredLoss(address indexed creditManager, uint256 loss);
/// @notice Emitted when new interest rate model contract is set
event SetInterestRateModel(address indexed newInterestRateModel);
/// @notice Emitted when new pool quota keeper contract is set
event SetPoolQuotaKeeper(address indexed newPoolQuotaKeeper);
/// @notice Emitted when new total debt limit is set
event SetTotalDebtLimit(uint256 limit);
/// @notice Emitted when new credit manager is connected to the pool
event AddCreditManager(address indexed creditManager);
/// @notice Emitted when new debt limit is set for a credit manager
event SetCreditManagerDebtLimit(address indexed creditManager, uint256 newLimit);
/// @notice Emitted when new withdrawal fee is set
event SetWithdrawFee(uint256 fee);
}
/// @title Pool V3 interface
interface IPoolV3 is IVersion, IACLTrait, IContractsRegisterTrait, IPoolV3Events, IERC4626, IERC20Permit {
function underlyingToken() external view returns (address);
function treasury() external view returns (address);
function withdrawFee() external view returns (uint16);
function creditManagers() external view returns (address[] memory);
function availableLiquidity() external view returns (uint256);
function expectedLiquidity() external view returns (uint256);
function expectedLiquidityLU() external view returns (uint256);
// ---------------- //
// ERC-4626 LENDING //
// ---------------- //
function depositWithReferral(uint256 assets, address receiver, uint256 referralCode)
external
returns (uint256 shares);
function mintWithReferral(uint256 shares, address receiver, uint256 referralCode)
external
returns (uint256 assets);
// --------- //
// BORROWING //
// --------- //
function totalBorrowed() external view returns (uint256);
function totalDebtLimit() external view returns (uint256);
function creditManagerBorrowed(address creditManager) external view returns (uint256);
function creditManagerDebtLimit(address creditManager) external view returns (uint256);
function creditManagerBorrowable(address creditManager) external view returns (uint256 borrowable);
function lendCreditAccount(uint256 borrowedAmount, address creditAccount) external;
function repayCreditAccount(uint256 repaidAmount, uint256 profit, uint256 loss) external;
// ------------- //
// INTEREST RATE //
// ------------- //
function interestRateModel() external view returns (address);
function baseInterestRate() external view returns (uint256);
function supplyRate() external view returns (uint256);
function baseInterestIndex() external view returns (uint256);
function baseInterestIndexLU() external view returns (uint256);
function lastBaseInterestUpdate() external view returns (uint40);
// ------ //
// QUOTAS //
// ------ //
function poolQuotaKeeper() external view returns (address);
function quotaRevenue() external view returns (uint256);
function lastQuotaRevenueUpdate() external view returns (uint40);
function updateQuotaRevenue(int256 quotaRevenueDelta) external;
function setQuotaRevenue(uint256 newQuotaRevenue) external;
// ------------- //
// CONFIGURATION //
// ------------- //
function setInterestRateModel(address newInterestRateModel) external;
function setPoolQuotaKeeper(address newPoolQuotaKeeper) external;
function setTotalDebtLimit(uint256 newLimit) external;
function setCreditManagerDebtLimit(address creditManager, uint256 newLimit) external;
function setWithdrawFee(uint256 newWithdrawFee) external;
function pause() external;
function unpause() external;
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {IACLTrait} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IACLTrait.sol";
import {IContractsRegister as IContractsRegisterBase} from
"@gearbox-protocol/core-v3/contracts/interfaces/base/IContractsRegister.sol";
import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol";
interface IContractsRegister is IContractsRegisterBase, IVersion, IACLTrait {
// ------ //
// EVENTS //
// ------ //
event RegisterMarket(address indexed pool, address indexed priceOracle, address indexed lossPolicy);
event ShutdownMarket(address indexed pool);
event RegisterCreditSuite(address indexed pool, address indexed creditManager);
event ShutdownCreditSuite(address indexed pool, address indexed creditManager);
event SetPriceOracle(address indexed pool, address indexed priceOracle);
event SetLossPolicy(address indexed pool, address indexed lossPolicy);
// ------ //
// ERRORS //
// ------ //
error MarketNotRegisteredException(address pool);
error MarketShutDownException(address pool);
error MarketNotEmptyException(address pool);
error CreditSuiteNotRegisteredException(address creditManager);
error CreditSuiteShutDownException(address creditManager);
// ------- //
// MARKETS //
// ------- //
function getShutdownPools() external view returns (address[] memory);
function getPriceOracle(address pool) external view returns (address);
function getLossPolicy(address pool) external view returns (address);
function registerMarket(address pool, address priceOracle, address lossPolicy) external;
function shutdownMarket(address pool) external;
function setPriceOracle(address pool, address priceOracle) external;
function setLossPolicy(address pool, address lossPolicy) external;
// ------------- //
// CREDIT SUITES //
// ------------- //
function getCreditManagers(address pool) external view returns (address[] memory);
function getShutdownCreditManagers() external view returns (address[] memory);
function getShutdownCreditManagers(address pool) external view returns (address[] memory);
function registerCreditSuite(address creditManager) external;
function shutdownCreditSuite(address creditManager) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for converting numbers into strings and other string operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
///
/// @dev Note:
/// For performance and bytecode compactness, most of the string operations are restricted to
/// byte strings (7-bit ASCII), except where otherwise specified.
/// Usage of byte string operations on charsets with runes spanning two or more bytes
/// can lead to undefined behavior.
library LibString {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The length of the output is too small to contain all the hex digits.
error HexLengthInsufficient();
/// @dev The length of the string is more than 32 bytes.
error TooBigForSmallString();
/// @dev The input string must be a 7-bit ASCII.
error StringNot7BitASCII();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the string.
uint256 internal constant NOT_FOUND = type(uint256).max;
/// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000;
/// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000;
/// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'.
uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000;
/// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000;
/// @dev Lookup for '0123456789'.
uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000;
/// @dev Lookup for '0123456789abcdefABCDEF'.
uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000;
/// @dev Lookup for '01234567'.
uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000;
/// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'.
uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00;
/// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'.
uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000;
/// @dev Lookup for ' \t\n\r\x0b\x0c'.
uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the base 10 decimal representation of `value`.
function toString(uint256 value) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but
// we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
// We will need 1 word for the trailing zeros padding, 1 word for the length,
// and 3 words for a maximum of 78 digits.
str := add(mload(0x40), 0x80)
// Update the free memory pointer to allocate.
mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end of the memory to calculate the length later.
let end := str
let w := not(0) // Tsk.
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let temp := value } 1 {} {
str := add(str, w) // `sub(str, 1)`.
// Write the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(str, add(48, mod(temp, 10)))
// Keep dividing `temp` until zero.
temp := div(temp, 10)
if iszero(temp) { break }
}
let length := sub(end, str)
// Move the pointer 32 bytes leftwards to make room for the length.
str := sub(str, 0x20)
// Store the length.
mstore(str, length)
}
}
/// @dev Returns the base 10 decimal representation of `value`.
function toString(int256 value) internal pure returns (string memory str) {
if (value >= 0) {
return toString(uint256(value));
}
unchecked {
str = toString(~uint256(value) + 1);
}
/// @solidity memory-safe-assembly
assembly {
// We still have some spare memory space on the left,
// as we have allocated 3 words (96 bytes) for up to 78 digits.
let length := mload(str) // Load the string length.
mstore(str, 0x2d) // Store the '-' character.
str := sub(str, 1) // Move back the string pointer by a byte.
mstore(str, add(length, 1)) // Update the string length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HEXADECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `length` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `length * 2 + 2` bytes.
/// Reverts if `length` is too small for the output to contain all the digits.
function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value, length);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `length` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `length * 2` bytes.
/// Reverts if `length` is too small for the output to contain all the digits.
function toHexStringNoPrefix(uint256 value, uint256 length)
internal
pure
returns (string memory str)
{
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes
// for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.
// We add 0x20 to the total and round down to a multiple of 0x20.
// (0x20 + 0x20 + 0x02 + 0x20) = 0x62.
str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))
// Allocate the memory.
mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end to calculate the length later.
let end := str
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let start := sub(str, add(length, length))
let w := not(1) // Tsk.
let temp := value
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for {} 1 {} {
str := add(str, w) // `sub(str, 2)`.
mstore8(add(str, 1), mload(and(temp, 15)))
mstore8(str, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(xor(str, start)) { break }
}
if temp {
mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
revert(0x1c, 0x04)
}
// Compute the string's length.
let strLength := sub(end, str)
// Move the pointer and write the length.
str := sub(str, 0x20)
mstore(str, strLength)
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
/// As address are 20 bytes long, the output will left-padded to have
/// a length of `20 * 2 + 2` bytes.
function toHexString(uint256 value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x".
/// The output excludes leading "0" from the `toHexString` output.
/// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`.
function toMinimalHexString(uint256 value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
let strLength := add(mload(str), 2) // Compute the length.
mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero.
str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.
mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output excludes leading "0" from the `toHexStringNoPrefix` output.
/// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`.
function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
let strLength := mload(str) // Get the length.
str := add(str, o) // Move the pointer, accounting for leading zero.
mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
/// As address are 20 bytes long, the output will left-padded to have
/// a length of `20 * 2` bytes.
function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x40 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.
str := add(mload(0x40), 0x80)
// Allocate the memory.
mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end to calculate the length later.
let end := str
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let w := not(1) // Tsk.
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let temp := value } 1 {} {
str := add(str, w) // `sub(str, 2)`.
mstore8(add(str, 1), mload(and(temp, 15)))
mstore8(str, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(temp) { break }
}
// Compute the string's length.
let strLength := sub(end, str)
// Move the pointer and write the length.
str := sub(str, 0x20)
mstore(str, strLength)
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
/// and the alphabets are capitalized conditionally according to
/// https://eips.ethereum.org/EIPS/eip-55
function toHexStringChecksummed(address value) internal pure returns (string memory str) {
str = toHexString(value);
/// @solidity memory-safe-assembly
assembly {
let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
let o := add(str, 0x22)
let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `
let t := shl(240, 136) // `0b10001000 << 240`
for { let i := 0 } 1 {} {
mstore(add(i, i), mul(t, byte(i, hashed)))
i := add(i, 1)
if eq(i, 20) { break }
}
mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
o := add(o, 0x20)
mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
function toHexString(address value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(address value) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
str := mload(0x40)
// Allocate the memory.
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x28 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
mstore(0x40, add(str, 0x80))
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
str := add(str, 2)
mstore(str, 40)
let o := add(str, 0x20)
mstore(add(o, 40), 0)
value := shl(96, value)
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let i := 0 } 1 {} {
let p := add(o, add(i, i))
let temp := byte(i, value)
mstore8(add(p, 1), mload(and(temp, 15)))
mstore8(p, mload(shr(4, temp)))
i := add(i, 1)
if eq(i, 20) { break }
}
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexString(bytes memory raw) internal pure returns (string memory str) {
str = toHexStringNoPrefix(raw);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
let length := mload(raw)
str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
mstore(str, add(length, length)) // Store the length of the output.
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let o := add(str, 0x20)
let end := add(raw, length)
for {} iszero(eq(raw, end)) {} {
raw := add(raw, 1)
mstore8(add(o, 1), mload(and(mload(raw), 15)))
mstore8(o, mload(and(shr(4, mload(raw)), 15)))
o := add(o, 2)
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate the memory.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RUNE STRING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the number of UTF characters in the string.
function runeCount(string memory s) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
if mload(s) {
mstore(0x00, div(not(0), 255))
mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)
let o := add(s, 0x20)
let end := add(o, mload(s))
for { result := 1 } 1 { result := add(result, 1) } {
o := add(o, byte(0, mload(shr(250, mload(o)))))
if iszero(lt(o, end)) { break }
}
}
}
}
/// @dev Returns if this string is a 7-bit ASCII string.
/// (i.e. all characters codes are in [0..127])
function is7BitASCII(string memory s) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
let mask := shl(7, div(not(0), 255))
result := 1
let n := mload(s)
if n {
let o := add(s, 0x20)
let end := add(o, n)
let last := mload(end)
mstore(end, 0)
for {} 1 {} {
if and(mask, mload(o)) {
result := 0
break
}
o := add(o, 0x20)
if iszero(lt(o, end)) { break }
}
mstore(end, last)
}
}
}
/// @dev Returns if this string is a 7-bit ASCII string,
/// AND all characters are in the `allowed` lookup.
/// Note: If `s` is empty, returns true regardless of `allowed`.
function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := 1
if mload(s) {
let allowed_ := shr(128, shl(128, allowed))
let o := add(s, 0x20)
let end := add(o, mload(s))
for {} 1 {} {
result := and(result, shr(byte(0, mload(o)), allowed_))
o := add(o, 1)
if iszero(and(result, lt(o, end))) { break }
}
}
}
}
/// @dev Converts the bytes in the 7-bit ASCII string `s` to
/// an allowed lookup for use in `is7BitASCII(s, allowed)`.
/// To save runtime gas, you can cache the result in an immutable variable.
function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) {
/// @solidity memory-safe-assembly
assembly {
if mload(s) {
let o := add(s, 0x20)
let end := add(o, mload(s))
for {} 1 {} {
result := or(result, shl(byte(0, mload(o)), 1))
o := add(o, 1)
if iszero(lt(o, end)) { break }
}
if shr(128, result) {
mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`.
revert(0x1c, 0x04)
}
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE STRING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// For performance and bytecode compactness, byte string operations are restricted
// to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.
// Usage of byte string operations on charsets with runes spanning two or more bytes
// can lead to undefined behavior.
/// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.
function replace(string memory subject, string memory search, string memory replacement)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
let searchLength := mload(search)
let replacementLength := mload(replacement)
subject := add(subject, 0x20)
search := add(search, 0x20)
replacement := add(replacement, 0x20)
result := add(mload(0x40), 0x20)
let subjectEnd := add(subject, subjectLength)
if iszero(gt(searchLength, subjectLength)) {
let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)
let h := 0
if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
let s := mload(search)
for {} 1 {} {
let t := mload(subject)
// Whether the first `searchLength % 32` bytes of
// `subject` and `search` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(subject, searchLength), h)) {
mstore(result, t)
result := add(result, 1)
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
// Copy the `replacement` one word at a time.
for { let o := 0 } 1 {} {
mstore(add(result, o), mload(add(replacement, o)))
o := add(o, 0x20)
if iszero(lt(o, replacementLength)) { break }
}
result := add(result, replacementLength)
subject := add(subject, searchLength)
if searchLength {
if iszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
mstore(result, t)
result := add(result, 1)
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) { break }
}
}
let resultRemainder := result
result := add(mload(0x40), 0x20)
let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))
// Copy the rest of the string one word at a time.
for {} lt(subject, subjectEnd) {} {
mstore(resultRemainder, mload(subject))
resultRemainder := add(resultRemainder, 0x20)
subject := add(subject, 0x20)
}
result := sub(result, 0x20)
let last := add(add(result, 0x20), k) // Zeroize the slot after the string.
mstore(last, 0)
mstore(0x40, add(last, 0x20)) // Allocate the memory.
mstore(result, k) // Store the length.
}
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function indexOf(string memory subject, string memory search, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
for { let subjectLength := mload(subject) } 1 {} {
if iszero(mload(search)) {
if iszero(gt(from, subjectLength)) {
result := from
break
}
result := subjectLength
break
}
let searchLength := mload(search)
let subjectStart := add(subject, 0x20)
result := not(0) // Initialize to `NOT_FOUND`.
subject := add(subjectStart, from)
let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)
let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
let s := mload(add(search, 0x20))
if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }
if iszero(lt(searchLength, 0x20)) {
for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
if eq(keccak256(subject, searchLength), h) {
result := sub(subject, subjectStart)
break
}
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
for {} 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
result := sub(subject, subjectStart)
break
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function indexOf(string memory subject, string memory search)
internal
pure
returns (uint256 result)
{
result = indexOf(subject, search, 0);
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function lastIndexOf(string memory subject, string memory search, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
result := not(0) // Initialize to `NOT_FOUND`.
let searchLength := mload(search)
if gt(searchLength, mload(subject)) { break }
let w := result
let fromMax := sub(mload(subject), searchLength)
if iszero(gt(fromMax, from)) { from := fromMax }
let end := add(add(subject, 0x20), w)
subject := add(add(subject, 0x20), from)
if iszero(gt(subject, end)) { break }
// As this function is not too often used,
// we shall simply use keccak256 for smaller bytecode size.
for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
if eq(keccak256(subject, searchLength), h) {
result := sub(subject, add(end, 1))
break
}
subject := add(subject, w) // `sub(subject, 1)`.
if iszero(gt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function lastIndexOf(string memory subject, string memory search)
internal
pure
returns (uint256 result)
{
result = lastIndexOf(subject, search, uint256(int256(-1)));
}
/// @dev Returns true if `search` is found in `subject`, false otherwise.
function contains(string memory subject, string memory search) internal pure returns (bool) {
return indexOf(subject, search) != NOT_FOUND;
}
/// @dev Returns whether `subject` starts with `search`.
function startsWith(string memory subject, string memory search)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let searchLength := mload(search)
// Just using keccak256 directly is actually cheaper.
// forgefmt: disable-next-item
result := and(
iszero(gt(searchLength, mload(subject))),
eq(
keccak256(add(subject, 0x20), searchLength),
keccak256(add(search, 0x20), searchLength)
)
)
}
}
/// @dev Returns whether `subject` ends with `search`.
function endsWith(string memory subject, string memory search)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let searchLength := mload(search)
let subjectLength := mload(subject)
// Whether `search` is not longer than `subject`.
let withinRange := iszero(gt(searchLength, subjectLength))
// Just using keccak256 directly is actually cheaper.
// forgefmt: disable-next-item
result := and(
withinRange,
eq(
keccak256(
// `subject + 0x20 + max(subjectLength - searchLength, 0)`.
add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),
searchLength
),
keccak256(add(search, 0x20), searchLength)
)
)
}
}
/// @dev Returns `subject` repeated `times`.
function repeat(string memory subject, uint256 times)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
if iszero(or(iszero(times), iszero(subjectLength))) {
subject := add(subject, 0x20)
result := mload(0x40)
let output := add(result, 0x20)
for {} 1 {} {
// Copy the `subject` one word at a time.
for { let o := 0 } 1 {} {
mstore(add(output, o), mload(add(subject, o)))
o := add(o, 0x20)
if iszero(lt(o, subjectLength)) { break }
}
output := add(output, subjectLength)
times := sub(times, 1)
if iszero(times) { break }
}
mstore(output, 0) // Zeroize the slot after the string.
let resultLength := sub(output, add(result, 0x20))
mstore(result, resultLength) // Store the length.
// Allocate the memory.
mstore(0x40, add(result, add(resultLength, 0x20)))
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function slice(string memory subject, uint256 start, uint256 end)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
if iszero(gt(subjectLength, end)) { end := subjectLength }
if iszero(gt(subjectLength, start)) { start := subjectLength }
if lt(start, end) {
result := mload(0x40)
let resultLength := sub(end, start)
mstore(result, resultLength)
subject := add(subject, start)
let w := not(0x1f)
// Copy the `subject` one word at a time, backwards.
for { let o := and(add(resultLength, 0x1f), w) } 1 {} {
mstore(add(result, o), mload(add(subject, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
// Zeroize the slot after the string.
mstore(add(add(result, 0x20), resultLength), 0)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the string.
/// `start` is a byte offset.
function slice(string memory subject, uint256 start)
internal
pure
returns (string memory result)
{
result = slice(subject, start, uint256(int256(-1)));
}
/// @dev Returns all the indices of `search` in `subject`.
/// The indices are byte offsets.
function indicesOf(string memory subject, string memory search)
internal
pure
returns (uint256[] memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
let searchLength := mload(search)
if iszero(gt(searchLength, subjectLength)) {
subject := add(subject, 0x20)
search := add(search, 0x20)
result := add(mload(0x40), 0x20)
let subjectStart := subject
let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)
let h := 0
if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
let s := mload(search)
for {} 1 {} {
let t := mload(subject)
// Whether the first `searchLength % 32` bytes of
// `subject` and `search` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(subject, searchLength), h)) {
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
// Append to `result`.
mstore(result, sub(subject, subjectStart))
result := add(result, 0x20)
// Advance `subject` by `searchLength`.
subject := add(subject, searchLength)
if searchLength {
if iszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) { break }
}
let resultEnd := result
// Assign `result` to the free memory pointer.
result := mload(0x40)
// Store the length of `result`.
mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))
// Allocate memory for result.
// We allocate one more word, so this array can be recycled for {split}.
mstore(0x40, add(resultEnd, 0x20))
}
}
}
/// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.
function split(string memory subject, string memory delimiter)
internal
pure
returns (string[] memory result)
{
uint256[] memory indices = indicesOf(subject, delimiter);
/// @solidity memory-safe-assembly
assembly {
let w := not(0x1f)
let indexPtr := add(indices, 0x20)
let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
mstore(add(indicesEnd, w), mload(subject))
mstore(indices, add(mload(indices), 1))
let prevIndex := 0
for {} 1 {} {
let index := mload(indexPtr)
mstore(indexPtr, 0x60)
if iszero(eq(index, prevIndex)) {
let element := mload(0x40)
let elementLength := sub(index, prevIndex)
mstore(element, elementLength)
// Copy the `subject` one word at a time, backwards.
for { let o := and(add(elementLength, 0x1f), w) } 1 {} {
mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
// Zeroize the slot after the string.
mstore(add(add(element, 0x20), elementLength), 0)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))
// Store the `element` into the array.
mstore(indexPtr, element)
}
prevIndex := add(index, mload(delimiter))
indexPtr := add(indexPtr, 0x20)
if iszero(lt(indexPtr, indicesEnd)) { break }
}
result := indices
if iszero(mload(delimiter)) {
result := add(indices, 0x20)
mstore(result, sub(mload(indices), 2))
}
}
}
/// @dev Returns a concatenated string of `a` and `b`.
/// Cheaper than `string.concat()` and does not de-align the free memory pointer.
function concat(string memory a, string memory b)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let w := not(0x1f)
result := mload(0x40)
let aLength := mload(a)
// Copy `a` one word at a time, backwards.
for { let o := and(add(aLength, 0x20), w) } 1 {} {
mstore(add(result, o), mload(add(a, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let bLength := mload(b)
let output := add(result, aLength)
// Copy `b` one word at a time, backwards.
for { let o := and(add(bLength, 0x20), w) } 1 {} {
mstore(add(output, o), mload(add(b, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let totalLength := add(aLength, bLength)
let last := add(add(result, 0x20), totalLength)
// Zeroize the slot after the string.
mstore(last, 0)
// Stores the length.
mstore(result, totalLength)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, and(add(last, 0x1f), w))
}
}
/// @dev Returns a copy of the string in either lowercase or UPPERCASE.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function toCase(string memory subject, bool toUpper)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let length := mload(subject)
if length {
result := add(mload(0x40), 0x20)
subject := add(subject, 1)
let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
let w := not(0)
for { let o := length } 1 {} {
o := add(o, w)
let b := and(0xff, mload(add(subject, o)))
mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))
if iszero(o) { break }
}
result := mload(0x40)
mstore(result, length) // Store the length.
let last := add(add(result, 0x20), length)
mstore(last, 0) // Zeroize the slot after the string.
mstore(0x40, add(last, 0x20)) // Allocate the memory.
}
}
}
/// @dev Returns a string from a small bytes32 string.
/// `s` must be null-terminated, or behavior will be undefined.
function fromSmallString(bytes32 s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let n := 0
for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'.
mstore(result, n)
let o := add(result, 0x20)
mstore(o, s)
mstore(add(o, n), 0)
mstore(0x40, add(result, 0x40))
}
}
/// @dev Returns the small string, with all bytes after the first null byte zeroized.
function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'.
mstore(0x00, s)
mstore(result, 0x00)
result := mload(0x00)
}
}
/// @dev Returns the string as a normalized null-terminated small string.
function toSmallString(string memory s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(s)
if iszero(lt(result, 33)) {
mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.
revert(0x1c, 0x04)
}
result := shl(shl(3, sub(32, result)), mload(add(s, result)))
}
}
/// @dev Returns a lowercased copy of the string.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function lower(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, false);
}
/// @dev Returns an UPPERCASED copy of the string.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function upper(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, true);
}
/// @dev Escapes the string to be used within HTML tags.
function escapeHTML(string memory s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
let end := add(s, mload(s))
result := add(mload(0x40), 0x20)
// Store the bytes of the packed offsets and strides into the scratch space.
// `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.
mstore(0x1f, 0x900094)
mstore(0x08, 0xc0000000a6ab)
// Store ""&'<>" into the scratch space.
mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
for {} iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
// Not in `["\"","'","&","<",">"]`.
if iszero(and(shl(c, 1), 0x500000c400000000)) {
mstore8(result, c)
result := add(result, 1)
continue
}
let t := shr(248, mload(c))
mstore(result, mload(and(t, 0x1f)))
result := add(result, shr(5, t))
}
let last := result
mstore(last, 0) // Zeroize the slot after the string.
result := mload(0x40)
mstore(result, sub(last, add(result, 0x20))) // Store the length.
mstore(0x40, add(last, 0x20)) // Allocate the memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.
/// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.
function escapeJSON(string memory s, bool addDoubleQuotes)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let end := add(s, mload(s))
result := add(mload(0x40), 0x20)
if addDoubleQuotes {
mstore8(result, 34)
result := add(1, result)
}
// Store "\\u0000" in scratch space.
// Store "0123456789abcdef" in scratch space.
// Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`.
// into the scratch space.
mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
// Bitmask for detecting `["\"","\\"]`.
let e := or(shl(0x22, 1), shl(0x5c, 1))
for {} iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
if iszero(lt(c, 0x20)) {
if iszero(and(shl(c, 1), e)) {
// Not in `["\"","\\"]`.
mstore8(result, c)
result := add(result, 1)
continue
}
mstore8(result, 0x5c) // "\\".
mstore8(add(result, 1), c)
result := add(result, 2)
continue
}
if iszero(and(shl(c, 1), 0x3700)) {
// Not in `["\b","\t","\n","\f","\d"]`.
mstore8(0x1d, mload(shr(4, c))) // Hex value.
mstore8(0x1e, mload(and(c, 15))) // Hex value.
mstore(result, mload(0x19)) // "\\u00XX".
result := add(result, 6)
continue
}
mstore8(result, 0x5c) // "\\".
mstore8(add(result, 1), mload(add(c, 8)))
result := add(result, 2)
}
if addDoubleQuotes {
mstore8(result, 34)
result := add(1, result)
}
let last := result
mstore(last, 0) // Zeroize the slot after the string.
result := mload(0x40)
mstore(result, sub(last, add(result, 0x20))) // Store the length.
mstore(0x40, add(last, 0x20)) // Allocate the memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.
function escapeJSON(string memory s) internal pure returns (string memory result) {
result = escapeJSON(s, false);
}
/// @dev Returns whether `a` equals `b`.
function eq(string memory a, string memory b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
}
}
/// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.
function eqs(string memory a, bytes32 b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// These should be evaluated on compile time, as far as possible.
let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
let x := not(or(m, or(b, add(m, and(b, m)))))
let r := shl(7, iszero(iszero(shr(128, x))))
r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
}
}
/// @dev Packs a single string with its length into a single word.
/// Returns `bytes32(0)` if the length is zero or greater than 31.
function packOne(string memory a) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
// We don't need to zero right pad the string,
// since this is our own custom non-standard packing scheme.
result :=
mul(
// Load the length and the bytes.
mload(add(a, 0x1f)),
// `length != 0 && length < 32`. Abuses underflow.
// Assumes that the length is valid and within the block gas limit.
lt(sub(mload(a), 1), 0x1f)
)
}
}
/// @dev Unpacks a string packed using {packOne}.
/// Returns the empty string if `packed` is `bytes32(0)`.
/// If `packed` is not an output of {packOne}, the output behavior is undefined.
function unpackOne(bytes32 packed) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
// Grab the free memory pointer.
result := mload(0x40)
// Allocate 2 words (1 for the length, 1 for the bytes).
mstore(0x40, add(result, 0x40))
// Zeroize the length slot.
mstore(result, 0)
// Store the length and bytes.
mstore(add(result, 0x1f), packed)
// Right pad with zeroes.
mstore(add(add(result, 0x20), mload(result)), 0)
}
}
/// @dev Packs two strings with their lengths into a single word.
/// Returns `bytes32(0)` if combined length is zero or greater than 30.
function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let aLength := mload(a)
// We don't need to zero right pad the strings,
// since this is our own custom non-standard packing scheme.
result :=
mul(
// Load the length and the bytes of `a` and `b`.
or(
shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),
mload(sub(add(b, 0x1e), aLength))
),
// `totalLength != 0 && totalLength < 31`. Abuses underflow.
// Assumes that the lengths are valid and within the block gas limit.
lt(sub(add(aLength, mload(b)), 1), 0x1e)
)
}
}
/// @dev Unpacks strings packed using {packTwo}.
/// Returns the empty strings if `packed` is `bytes32(0)`.
/// If `packed` is not an output of {packTwo}, the output behavior is undefined.
function unpackTwo(bytes32 packed)
internal
pure
returns (string memory resultA, string memory resultB)
{
/// @solidity memory-safe-assembly
assembly {
// Grab the free memory pointer.
resultA := mload(0x40)
resultB := add(resultA, 0x40)
// Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.
mstore(0x40, add(resultB, 0x40))
// Zeroize the length slots.
mstore(resultA, 0)
mstore(resultB, 0)
// Store the lengths and bytes.
mstore(add(resultA, 0x1f), packed)
mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
// Right pad with zeroes.
mstore(add(add(resultA, 0x20), mload(resultA)), 0)
mstore(add(add(resultB, 0x20), mload(resultB)), 0)
}
}
/// @dev Directly returns `a` without copying.
function directReturn(string memory a) internal pure {
assembly {
// Assumes that the string does not start from the scratch space.
let retStart := sub(a, 0x20)
let retUnpaddedSize := add(mload(a), 0x40)
// Right pad with zeroes. Just in case the string is produced
// by a method that doesn't zero right pad.
mstore(add(retStart, retUnpaddedSize), 0)
// Store the return offset.
mstore(retStart, 0x20)
// End the transaction, returning the string.
return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
}
}
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {IAddressProvider as IAddressProviderBase} from
"@gearbox-protocol/core-v3/contracts/interfaces/base/IAddressProvider.sol";
import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol";
import {IImmutableOwnableTrait} from "./base/IImmutableOwnableTrait.sol";
import {AddressProviderEntry} from "./Types.sol";
/// @title Address provider interface
interface IAddressProvider is IAddressProviderBase, IVersion, IImmutableOwnableTrait {
// ------ //
// EVENTS //
// ------ //
event SetAddress(bytes32 indexed key, uint256 indexed ver, address indexed value);
// ------ //
// ERRORS //
// ------ //
error AddressNotFoundException(bytes32 key, uint256 ver);
error InvalidVersionException(bytes32 key, uint256 ver);
error VersionNotFoundException(bytes32 key);
error ZeroAddressException(bytes32 key);
// ------- //
// GETTERS //
// ------- //
function getAddress(bytes32 key, uint256 ver) external view returns (address);
function getAddressOrRevert(bytes32 key, uint256 ver) external view override returns (address);
function getKeys() external view returns (bytes32[] memory);
function getVersions(bytes32 key) external view returns (uint256[] memory);
function getAllEntries() external view returns (AddressProviderEntry[] memory);
function getLatestVersion(bytes32 key) external view returns (uint256);
function getLatestMinorVersion(bytes32 key, uint256 majorVersion) external view returns (uint256);
function getLatestPatchVersion(bytes32 key, uint256 minorVersion) external view returns (uint256);
// ------------- //
// CONFIGURATION //
// ------------- //
function setAddress(bytes32 key, address value, bool saveVersion) external;
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol";
import {IImmutableOwnableTrait} from "./base/IImmutableOwnableTrait.sol";
import {AuditReport, Bytecode} from "./Types.sol";
/// @title Bytecode repository interface
interface IBytecodeRepository is IVersion, IImmutableOwnableTrait {
// ------ //
// EVENTS //
// ------ //
event AddAuditor(address indexed auditor, string name);
event AddPublicDomain(bytes32 indexed domain);
event AddSystemDomain(bytes32 indexed domain);
event AllowContract(bytes32 indexed bytecodeHash, bytes32 indexed contractType, uint256 indexed version);
event AuditBytecode(bytes32 indexed bytecodeHash, address indexed auditor, string reportUrl, bytes signature);
event DeployContract(
bytes32 indexed bytecodeHash, bytes32 indexed contractType, uint256 indexed version, address contractAddress
);
event ForbidContract(bytes32 indexed bytecodeHash, bytes32 indexed contractType, uint256 indexed version);
event ForbidInitCode(bytes32 indexed initCodeHash);
event RemoveAuditor(address indexed auditor);
event RemoveContractTypeOwner(bytes32 indexed contractType);
event SetContractTypeOwner(bytes32 indexed contractType, address indexed owner);
event SetTokenSpecificPostfix(address indexed token, bytes32 indexed postfix);
event UploadBytecode(
bytes32 indexed bytecodeHash,
bytes32 indexed contractType,
uint256 indexed version,
address author,
string source,
bytes signature
);
// ------ //
// ERRORS //
// ------ //
error AuditorIsNotApprovedException(address auditor);
error AuthorIsNotContractTypeOwnerException(bytes32 contractType, address author);
error BytecodeIsAlreadyAllowedException(bytes32 contractType, uint256 version);
error BytecodeIsAlreadySignedByAuditorException(bytes32 bytecodeHash, address auditor);
error BytecodeIsNotAllowedException(bytes32 contractType, uint256 version);
error BytecodeIsNotAuditedException(bytes32 bytecodeHash);
error BytecodeIsNotUploadedException(bytes32 bytecodeHash);
error CallerIsNotBytecodeAuthorException(address caller);
error ContractIsAlreadyDeployedException(address deployedContract);
error ContractTypeIsNotInPublicDomainException(bytes32 contractType);
error DomainIsAlreadyMarketAsPublicException(bytes32 domain);
error DomainIsAlreadyMarketAsSystemException(bytes32 domain);
error InitCodeIsForbiddenException(bytes32 initCodeHash);
error InvalidAuditorSignatureException(address auditor);
error InvalidAuthorSignatureException(address author);
error InvalidBytecodeException(bytes32 bytecodeHash);
error InvalidContractTypeException(bytes32 contractType);
error InvalidDomainException(bytes32 domain);
error InvalidVersionException(bytes32 contractType, uint256 version);
error VersionNotFoundException(bytes32 contractType);
// --------------- //
// EIP-712 GETTERS //
// --------------- //
function BYTECODE_TYPEHASH() external view returns (bytes32);
function AUDIT_REPORT_TYPEHASH() external view returns (bytes32);
function domainSeparatorV4() external view returns (bytes32);
function computeBytecodeHash(Bytecode calldata bytecode) external view returns (bytes32);
function computeAuditReportHash(bytes32 bytecodeHash, address auditor, string calldata reportUrl)
external
view
returns (bytes32);
// ------------------- //
// DEPLOYING CONTRACTS //
// ------------------- //
function isDeployedFromRepository(address deployedContract) external view returns (bool);
function getDeployedContractBytecodeHash(address deployedContract) external view returns (bytes32);
function computeAddress(
bytes32 contractType,
uint256 version,
bytes calldata constructorParams,
bytes32 salt,
address deployer
) external view returns (address);
function deploy(bytes32 contractType, uint256 version, bytes calldata constructorParams, bytes32 salt)
external
returns (address);
// ------------------ //
// UPLOADING BYTECODE //
// ------------------ //
function getBytecode(bytes32 bytecodeHash) external view returns (Bytecode memory);
function isBytecodeUploaded(bytes32 bytecodeHash) external view returns (bool);
function uploadBytecode(Bytecode calldata bytecode) external;
// ----------------- //
// AUDITING BYTECODE //
// ----------------- //
function isBytecodeAudited(bytes32 bytecodeHash) external view returns (bool);
function getAuditReports(bytes32 bytecodeHash) external view returns (AuditReport[] memory);
function getAuditReport(bytes32 bytecodeHash, uint256 index) external view returns (AuditReport memory);
function getNumAuditReports(bytes32 bytecodeHash) external view returns (uint256);
function submitAuditReport(bytes32 bytecodeHash, AuditReport calldata auditReport) external;
// ----------------- //
// ALLOWING BYTECODE //
// ----------------- //
function getAllowedBytecodeHash(bytes32 contractType, uint256 version) external view returns (bytes32);
function getContractTypeOwner(bytes32 contractType) external view returns (address);
function allowSystemContract(bytes32 bytecodeHash) external;
function allowPublicContract(bytes32 bytecodeHash) external;
function removePublicContractType(bytes32 contractType) external;
// ------------------ //
// DOMAINS MANAGEMENT //
// ------------------ //
function isSystemDomain(bytes32 domain) external view returns (bool);
function getSystemDomains() external view returns (bytes32[] memory);
function isPublicDomain(bytes32 domain) external view returns (bool);
function getPublicDomains() external view returns (bytes32[] memory);
function addPublicDomain(bytes32 domain) external;
// ------------------- //
// AUDITORS MANAGEMENT //
// ------------------- //
function isAuditor(address auditor) external view returns (bool);
function getAuditors() external view returns (address[] memory);
function getAuditorName(address auditor) external view returns (string memory);
function addAuditor(address auditor, string calldata name) external;
function removeAuditor(address auditor) external;
// -------------------- //
// FORBIDDING INIT CODE //
// -------------------- //
function isInitCodeForbidden(bytes32 initCodeHash) external view returns (bool);
function forbidInitCode(bytes32 initCodeHash) external;
// ------------------------ //
// TOKENS WITH CUSTOM LOGIC //
// ------------------------ //
function getTokenSpecificPostfix(address token) external view returns (bytes32);
function setTokenSpecificPostfix(address token, bytes32 postfix) external;
// --------------- //
// VERSION CONTROL //
// --------------- //
function getVersions(bytes32 contractType) external view returns (uint256[] memory);
function getLatestVersion(bytes32 contractType) external view returns (uint256);
function getLatestMinorVersion(bytes32 contractType, uint256 majorVersion) external view returns (uint256);
function getLatestPatchVersion(bytes32 contractType, uint256 minorVersion) external view returns (uint256);
}// SPDX-License-Identifier: BUSL-1.1
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
import {LibString} from "@solady/utils/LibString.sol";
library Domain {
using LibString for string;
using LibString for bytes32;
uint128 internal constant UNDERSCORE = 1 << 95;
function getContractType(bytes32 domain, bytes32 postfix) internal pure returns (bytes32) {
if (postfix == 0) return domain;
return string.concat(domain.fromSmallString(), "::", postfix.fromSmallString()).toSmallString();
}
function extractDomain(bytes32 contractType) internal pure returns (bytes32) {
string memory str = contractType.fromSmallString();
uint256 separatorIndex = str.indexOf("::");
// If no separator found, treat the whole type as domain
if (separatorIndex == LibString.NOT_FOUND) return str.toSmallString();
return str.slice(0, separatorIndex).toSmallString();
}
function extractPostfix(bytes32 contractType) internal pure returns (bytes32) {
string memory str = contractType.fromSmallString();
uint256 separatorIndex = str.indexOf("::");
// if no separator found, return empty postfix
if (separatorIndex == LibString.NOT_FOUND) return bytes32(0);
return str.slice(separatorIndex + 2).toSmallString();
}
function isValidContractType(bytes32 contractType) internal pure returns (bool) {
bytes32 domain = extractDomain(contractType);
if (!isValidDomain(domain)) return false;
bytes32 postfix = extractPostfix(contractType);
if (!isValidPostfix(postfix)) return false;
// avoid the "DOMAIN::" case
return contractType == getContractType(domain, postfix);
}
function isValidDomain(bytes32 domain) internal pure returns (bool) {
return domain != 0 && _isValidString(domain.fromSmallString());
}
function isValidPostfix(bytes32 postfix) internal pure returns (bool) {
return _isValidString(postfix.fromSmallString());
}
function _isValidString(string memory str) internal pure returns (bool) {
return str.is7BitASCII(LibString.ALPHANUMERIC_7_BIT_ASCII | UNDERSCORE);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;
interface IContractsRegisterTrait {
function contractsRegister() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.0;
import "../token/ERC20/IERC20.sol";
import "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*
* _Available since v4.7._
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;
interface IContractsRegister {
function isPool(address) external view returns (bool);
function getPools() external view returns (address[] memory);
function isCreditManager(address) external view returns (bool);
function getCreditManagers() external view returns (address[] memory);
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;
interface IAddressProvider {
function getAddressOrRevert(bytes32 key, uint256 version) external view returns (address);
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;
/// @title Immutable ownable trait interface
/// @notice Interface for contracts with immutable owner functionality
interface IImmutableOwnableTrait {
error CallerIsNotOwnerException(address caller);
/// @notice Returns the immutable owner address
function owner() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}{
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"@1inch/=lib/@1inch/",
"@openzeppelin/=lib/@openzeppelin/",
"@gearbox-protocol/=lib/@gearbox-protocol/",
"@redstone-finance/=node_modules/@redstone-finance/",
"@solady/=lib/@solady/src/",
"erc4626-tests/=lib/@openzeppelin/lib/erc4626-tests/",
"openzeppelin/=lib/@openzeppelin/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 1000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "shanghai",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"addressProvider_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotMarketConfiguratorException","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"ForbiddenConfigurationCallException","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"ForbiddenEmergencyConfigurationCallException","type":"error"},{"inputs":[],"name":"InvalidConstructorParamsException","type":"error"},{"inputs":[],"name":"addressProvider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bytecodeRepository","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"configure","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Call[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractType","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"components":[{"internalType":"bytes32","name":"postfix","type":"bytes32"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"bytes","name":"constructorParams","type":"bytes"}],"internalType":"struct DeployParams","name":"params","type":"tuple"}],"name":"deployRateKeeper","outputs":[{"components":[{"internalType":"address","name":"newContract","type":"address"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Call[]","name":"onInstallOps","type":"tuple[]"}],"internalType":"struct DeployResult","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"emergencyConfigure","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Call[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"gearStaking","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketConfiguratorFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"onAddToken","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Call[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"onCreateCreditSuite","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Call[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"rateKeeper","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"onCreateMarket","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Call[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"onShutdownCreditSuite","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Call[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"onShutdownMarket","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Call[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"onUpdateInterestRateModel","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Call[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"onUpdateLossPolicy","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Call[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"onUpdatePriceOracle","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Call[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"newRateKeeper","type":"address"},{"internalType":"address","name":"oldRateKeeper","type":"address"}],"name":"onUpdateRateKeeper","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
0x61010060405234801562000011575f80fd5b50604051620019a3380380620019a383398101604081905262000034916200015f565b6001600160a01b03811660805280806200006f7f42595445434f44455f5245504f5349544f5259000000000000000000000000005f620000e3565b6001600160a01b031660a05250620000a87f4d41524b45545f434f4e464947555241544f525f464143544f525900000000005f620000e3565b6001600160a01b031660c05250620000d06b474541525f5354414b494e4760a01b5f620000e3565b6001600160a01b031660e0525062000187565b608051604051632bdad0e360e11b815260048101849052602481018390525f916001600160a01b0316906357b5a1c690604401602060405180830381865afa15801562000132573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200015891906200015f565b9392505050565b5f6020828403121562000170575f80fd5b81516001600160a01b038116811462000158575f80fd5b60805160a05160c05160e0516117c5620001de5f395f8181610263015261041d01525f81816101ea0152610bbd01525f818161022801528181611090015261113301525f81816101780152610ca601526117c55ff3fe608060405234801561000f575f80fd5b506004361061012f575f3560e01c806360e93cfd116100ad5780638e6a88231161007d578063cb2ef6f711610063578063cb2ef6f7146102ab578063d271bc5b146102d2578063f605bf6c146102e5575f80fd5b80638e6a88231461024a578063b3e035b214610298575f80fd5b806360e93cfd1461022357806361aa853d1461024a57806372b192591461025e5780637f85c18114610285575f80fd5b80632a82d9e5116101025780633ecc6e7d116100e85780633ecc6e7d146101e55780634abf9f591461013357806354fd4d501461020c575f80fd5b80632a82d9e5146101b25780633b790700146101c5575f80fd5b80631177eee514610133578063224b5eea1461016057806325680c1b146101335780632954018c14610173575b5f80fd5b61014a61014136600461121f565b60609392505050565b6040516101579190611327565b60405180910390f35b61014a61016e366004611339565b6102f8565b61019a7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610157565b61014a6101c03660046113b7565b610345565b6101d86101d33660046113d2565b61039b565b6040516101579190611425565b61019a7f000000000000000000000000000000000000000000000000000000000000000081565b61021561013681565b604051908152602001610157565b61019a7f000000000000000000000000000000000000000000000000000000000000000081565b61014a6102583660046113b7565b50606090565b61019a7f000000000000000000000000000000000000000000000000000000000000000081565b61014a61029336600461121f565b610671565b61014a6102a636600461145a565b610853565b6102157f524154455f4b45455045525f464143544f52590000000000000000000000000081565b61014a6102e036600461121f565b6108a3565b61014a6102f336600461145a565b6108d3565b606061030384610997565b71524154455f4b45455045523a3a474155474560701b036103375761033061032b855f610a17565b610a8e565b905061033b565b5060605b9695505050505050565b60605f61035961035484610af1565b610b52565b905061036481610997565b71524154455f4b45455045523a3a474155474560701b036103945761038d61032b826001610a17565b9392505050565b606061038d565b604080518082019091525f8152606060208201526103b7610b8f565b81357f474155474500000000000000000000000000000000000000000000000000000003610477575f806103ee60408501856114d8565b8101906103fb9190611522565b91509150846001600160a01b0316826001600160a01b031614158061045257507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614155b156104705760405163c429e07560e01b815260040160405180910390fd5b505061050b565b81357f54554d424c455200000000000000000000000000000000000000000000000000036104f5575f6104ad60408401846114d8565b8101906104ba919061154e565b509050836001600160a01b0316816001600160a01b0316146104ef5760405163c429e07560e01b815260040160405180910390fd5b5061050b565b61050b8361050660408501856114d8565b610c68565b5f6105c061053a7f524154455f4b45455045520000000000000000000000000000000000000000008535610d00565b61013661054a60408701876114d8565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250506040516105a592506020808b013592503391019182526001600160a01b0316602082015260400190565b60405160208183030381529060405280519060200120610d0b565b6040805180820182526001600160a01b03808416808352835180850185525f81526060602091820152845180860186523381528551306024820152938b16604485015260648085019390935285518085039093018352608490930190945280840180516001600160e01b03167f33598cf20000000000000000000000000000000000000000000000000000000017905281840152929350919082019061066590610a8e565b90529150505b92915050565b60605f61068561068086610af1565b610d21565b80519091508067ffffffffffffffff8111156106a3576106a3611578565b6040519080825280602002602001820160405280156106e857816020015b604080518082019091525f8152606060208201528152602001906001900390816106c15790505b5092505f6106f586610997565b90505f5b8281101561074a57610725878583815181106107175761071761158c565b602002602001015184610d85565b8582815181106107375761073761158c565b60209081029190910101526001016106f9565b5061075485610997565b71524154455f4b45455045523a3a474155474560701b036107875761078461077d866001610a17565b8590610e6b565b93505b8071524154455f4b45455045523a3a474155474560701b036107b3576107b061077d875f610a17565b93505b6040805180820182525f815260606020918201528151808301835233815282513060248201526001600160a01b03808c166044830152891660648083019190915284518083039091018152608490910190935282820180516001600160e01b03167f0ea2699200000000000000000000000000000000000000000000000000000000179052908101919091526108489061077d565b979650505050505050565b606061085f82846115a0565b6040517f2222fbf80000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024015b60405180910390fd5b60605f6108b261035486610af1565b90506108ca61032b82866108c585610997565b610d85565b95945050505050565b60605f6108e261035486610af1565b90505f6108ef84866115a0565b90506108fb8282610f4a565b1561093e576040517fa09bfd7d0000000000000000000000000000000000000000000000000000000081526001600160e01b03198216600482015260240161089a565b61033b6040518060400160405280846001600160a01b0316815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050915250610a8e565b5f816001600160a01b031663cb2ef6f76040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156109f2575060408051601f3d908101601f191682019092526109ef918101906115d0565b60015b61066b575071524154455f4b45455045523a3a474155474560701b919050565b919050565b604080518082019091525f8152606060208201526040518060400160405280846001600160a01b0316815260200183604051602401610a5a911515815260200190565b60408051601f198184030181529190526020810180516001600160e01b0316633b54651d60e21b1790529052905092915050565b604080516001808252818301909252606091816020015b604080518082019091525f815260606020820152815260200190600190039081610aa557905050905081815f81518110610ae157610ae161158c565b6020026020010181905250919050565b5f816001600160a01b031663be8da14b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b2e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061066b91906115f2565b5f816001600160a01b031663a6f19c846040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b2e573d5f803e3d5ffd5b6040517f7b731af80000000000000000000000000000000000000000000000000000000081523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690637b731af890602401602060405180830381865afa158015610c0a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c2e919061160d565b610c66576040517f7360e36000000000000000000000000000000000000000000000000000000000815233600482015260240161089a565b565b5f80610c77604082858761162c565b810190610c849190611522565b91509150846001600160a01b0316826001600160a01b0316141580610cdb57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614155b15610cf95760405163c429e07560e01b815260040160405180910390fd5b5050505050565b5f61038d838361100f565b5f6108ca85610d1a8787611058565b8585611101565b6060816001600160a01b031663582792376040518163ffffffff1660e01b81526004015f60405180830381865afa158015610d5e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261066b9190810190611653565b604080518082019091525f8152606060208201526040518060400160405280856001600160a01b031681526020018371524154455f4b45455045523a3a474155474560701b14610e13576040516001600160a01b038616602482015260440160408051601f198184030181529190526020810180516001600160e01b031663d48bfca760e01b179052610e61565b6040516001600160a01b0386166024820152600160448201819052606482015260840160408051601f198184030181529190526020810180516001600160e01b031663359cd5bf60e01b1790525b9052949350505050565b8151606090610e7b816001611713565b67ffffffffffffffff811115610e9357610e93611578565b604051908082528060200260200182016040528015610ed857816020015b604080518082019091525f815260606020820152815260200190600190039081610eb15790505b5091505f5b81811015610f2457848181518110610ef757610ef761158c565b6020026020010151838281518110610f1157610f1161158c565b6020908102919091010152600101610edd565b5082828281518110610f3857610f3861158c565b60200260200101819052505092915050565b5f610f5483610997565b71524154455f4b45455045523a3a474155474560701b03610ff4576001600160e01b0319821663d48bfca760e01b1480610f9e57506001600160e01b0319821663359cd5bf60e01b145b80610fb957506001600160e01b03198216633b54651d60e21b145b80610fed57506001600160e01b031982167f92eefe9b00000000000000000000000000000000000000000000000000000000145b905061066b565b506001600160e01b0319811663d48bfca760e01b1492915050565b5f81810361101e57508161066b565b61038d61102a846111ae565b611033846111ae565b604051602001611044929190611732565b6040516020818303038152906040526111e0565b6040517f4ceff70e00000000000000000000000000000000000000000000000000000000815260048101839052602481018290525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690634ceff70e90604401602060405180830381865afa1580156110dd573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061038d91906115d0565b6040517f5ce8938f0000000000000000000000000000000000000000000000000000000081525f906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635ce8938f9061116e908890889088908890600401611789565b6020604051808303815f875af115801561118a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108ca91906115f2565b6040515f5b82811a156111c3576001016111b3565b808252602082018381525f82820152505060408101604052919050565b8051602181106111f75763ec92f9a35f526004601cfd5b9081015160209190910360031b1b90565b6001600160a01b038116811461121c575f80fd5b50565b5f805f60608486031215611231575f80fd5b833561123c81611208565b9250602084013561124c81611208565b9150604084013561125c81611208565b809150509250925092565b5f5b83811015611281578181015183820152602001611269565b50505f910152565b5f81518084526112a0816020860160208601611267565b601f01601f19169290920160200192915050565b5f82825180855260208086019550808260051b8401018186015f5b8481101561131a57858303601f19018952815180516001600160a01b03168452840151604085850181905261130681860183611289565b9a86019a94505050908301906001016112cf565b5090979650505050505050565b602081525f61038d60208301846112b4565b5f805f805f8060c0878903121561134e575f80fd5b863561135981611208565b9550602087013561136981611208565b9450604087013561137981611208565b9350606087013561138981611208565b9250608087013561139981611208565b915060a08701356113a981611208565b809150509295509295509295565b5f602082840312156113c7575f80fd5b813561038d81611208565b5f80604083850312156113e3575f80fd5b82356113ee81611208565b9150602083013567ffffffffffffffff811115611409575f80fd5b83016060818603121561141a575f80fd5b809150509250929050565b602081526001600160a01b0382511660208201525f602083015160408084015261145260608401826112b4565b949350505050565b5f805f6040848603121561146c575f80fd5b833561147781611208565b9250602084013567ffffffffffffffff80821115611493575f80fd5b818601915086601f8301126114a6575f80fd5b8135818111156114b4575f80fd5b8760208285010111156114c5575f80fd5b6020830194508093505050509250925092565b5f808335601e198436030181126114ed575f80fd5b83018035915067ffffffffffffffff821115611507575f80fd5b60200191503681900382131561151b575f80fd5b9250929050565b5f8060408385031215611533575f80fd5b823561153e81611208565b9150602083013561141a81611208565b5f806040838503121561155f575f80fd5b823561156a81611208565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b6001600160e01b031981358181169160048510156115c85780818660040360031b1b83161692505b505092915050565b5f602082840312156115e0575f80fd5b5051919050565b8051610a1281611208565b5f60208284031215611602575f80fd5b815161038d81611208565b5f6020828403121561161d575f80fd5b8151801515811461038d575f80fd5b5f808585111561163a575f80fd5b83861115611646575f80fd5b5050820193919092039150565b5f6020808385031215611664575f80fd5b825167ffffffffffffffff8082111561167b575f80fd5b818501915085601f83011261168e575f80fd5b8151818111156116a0576116a0611578565b8060051b604051601f19603f830116810181811085821117156116c5576116c5611578565b6040529182528482019250838101850191888311156116e2575f80fd5b938501935b82851015611707576116f8856115e7565b845293850193928501926116e7565b98975050505050505050565b8082018082111561066b57634e487b7160e01b5f52601160045260245ffd5b5f8351611743818460208801611267565b7f3a3a000000000000000000000000000000000000000000000000000000000000908301908152835161177d816002840160208801611267565b01600201949350505050565b848152836020820152608060408201525f6117a76080830185611289565b90508260608301529594505050505056fea164736f6c6343000817000a000000000000000000000000ab8d55747b8d15b9c55eab0818b5142c596d4a35
Deployed Bytecode
0x608060405234801561000f575f80fd5b506004361061012f575f3560e01c806360e93cfd116100ad5780638e6a88231161007d578063cb2ef6f711610063578063cb2ef6f7146102ab578063d271bc5b146102d2578063f605bf6c146102e5575f80fd5b80638e6a88231461024a578063b3e035b214610298575f80fd5b806360e93cfd1461022357806361aa853d1461024a57806372b192591461025e5780637f85c18114610285575f80fd5b80632a82d9e5116101025780633ecc6e7d116100e85780633ecc6e7d146101e55780634abf9f591461013357806354fd4d501461020c575f80fd5b80632a82d9e5146101b25780633b790700146101c5575f80fd5b80631177eee514610133578063224b5eea1461016057806325680c1b146101335780632954018c14610173575b5f80fd5b61014a61014136600461121f565b60609392505050565b6040516101579190611327565b60405180910390f35b61014a61016e366004611339565b6102f8565b61019a7f000000000000000000000000ab8d55747b8d15b9c55eab0818b5142c596d4a3581565b6040516001600160a01b039091168152602001610157565b61014a6101c03660046113b7565b610345565b6101d86101d33660046113d2565b61039b565b6040516101579190611425565b61019a7f0000000000000000000000002bc29a2523690a5101c1615468cc0b792c18aeb681565b61021561013681565b604051908152602001610157565b61019a7f0000000000000000000000009700a405aff956f0baafc0a7ec57b71e656d5d9b81565b61014a6102583660046113b7565b50606090565b61019a7f0000000000000000000000002fcbd02d5b1d52fc78d4c02890d7f4f47a459c3381565b61014a61029336600461121f565b610671565b61014a6102a636600461145a565b610853565b6102157f524154455f4b45455045525f464143544f52590000000000000000000000000081565b61014a6102e036600461121f565b6108a3565b61014a6102f336600461145a565b6108d3565b606061030384610997565b71524154455f4b45455045523a3a474155474560701b036103375761033061032b855f610a17565b610a8e565b905061033b565b5060605b9695505050505050565b60605f61035961035484610af1565b610b52565b905061036481610997565b71524154455f4b45455045523a3a474155474560701b036103945761038d61032b826001610a17565b9392505050565b606061038d565b604080518082019091525f8152606060208201526103b7610b8f565b81357f474155474500000000000000000000000000000000000000000000000000000003610477575f806103ee60408501856114d8565b8101906103fb9190611522565b91509150846001600160a01b0316826001600160a01b031614158061045257507f0000000000000000000000002fcbd02d5b1d52fc78d4c02890d7f4f47a459c336001600160a01b0316816001600160a01b031614155b156104705760405163c429e07560e01b815260040160405180910390fd5b505061050b565b81357f54554d424c455200000000000000000000000000000000000000000000000000036104f5575f6104ad60408401846114d8565b8101906104ba919061154e565b509050836001600160a01b0316816001600160a01b0316146104ef5760405163c429e07560e01b815260040160405180910390fd5b5061050b565b61050b8361050660408501856114d8565b610c68565b5f6105c061053a7f524154455f4b45455045520000000000000000000000000000000000000000008535610d00565b61013661054a60408701876114d8565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250506040516105a592506020808b013592503391019182526001600160a01b0316602082015260400190565b60405160208183030381529060405280519060200120610d0b565b6040805180820182526001600160a01b03808416808352835180850185525f81526060602091820152845180860186523381528551306024820152938b16604485015260648085019390935285518085039093018352608490930190945280840180516001600160e01b03167f33598cf20000000000000000000000000000000000000000000000000000000017905281840152929350919082019061066590610a8e565b90529150505b92915050565b60605f61068561068086610af1565b610d21565b80519091508067ffffffffffffffff8111156106a3576106a3611578565b6040519080825280602002602001820160405280156106e857816020015b604080518082019091525f8152606060208201528152602001906001900390816106c15790505b5092505f6106f586610997565b90505f5b8281101561074a57610725878583815181106107175761071761158c565b602002602001015184610d85565b8582815181106107375761073761158c565b60209081029190910101526001016106f9565b5061075485610997565b71524154455f4b45455045523a3a474155474560701b036107875761078461077d866001610a17565b8590610e6b565b93505b8071524154455f4b45455045523a3a474155474560701b036107b3576107b061077d875f610a17565b93505b6040805180820182525f815260606020918201528151808301835233815282513060248201526001600160a01b03808c166044830152891660648083019190915284518083039091018152608490910190935282820180516001600160e01b03167f0ea2699200000000000000000000000000000000000000000000000000000000179052908101919091526108489061077d565b979650505050505050565b606061085f82846115a0565b6040517f2222fbf80000000000000000000000000000000000000000000000000000000081526001600160e01b031990911660048201526024015b60405180910390fd5b60605f6108b261035486610af1565b90506108ca61032b82866108c585610997565b610d85565b95945050505050565b60605f6108e261035486610af1565b90505f6108ef84866115a0565b90506108fb8282610f4a565b1561093e576040517fa09bfd7d0000000000000000000000000000000000000000000000000000000081526001600160e01b03198216600482015260240161089a565b61033b6040518060400160405280846001600160a01b0316815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050915250610a8e565b5f816001600160a01b031663cb2ef6f76040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156109f2575060408051601f3d908101601f191682019092526109ef918101906115d0565b60015b61066b575071524154455f4b45455045523a3a474155474560701b919050565b919050565b604080518082019091525f8152606060208201526040518060400160405280846001600160a01b0316815260200183604051602401610a5a911515815260200190565b60408051601f198184030181529190526020810180516001600160e01b0316633b54651d60e21b1790529052905092915050565b604080516001808252818301909252606091816020015b604080518082019091525f815260606020820152815260200190600190039081610aa557905050905081815f81518110610ae157610ae161158c565b6020026020010181905250919050565b5f816001600160a01b031663be8da14b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b2e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061066b91906115f2565b5f816001600160a01b031663a6f19c846040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b2e573d5f803e3d5ffd5b6040517f7b731af80000000000000000000000000000000000000000000000000000000081523360048201527f0000000000000000000000002bc29a2523690a5101c1615468cc0b792c18aeb66001600160a01b031690637b731af890602401602060405180830381865afa158015610c0a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c2e919061160d565b610c66576040517f7360e36000000000000000000000000000000000000000000000000000000000815233600482015260240161089a565b565b5f80610c77604082858761162c565b810190610c849190611522565b91509150846001600160a01b0316826001600160a01b0316141580610cdb57507f000000000000000000000000ab8d55747b8d15b9c55eab0818b5142c596d4a356001600160a01b0316816001600160a01b031614155b15610cf95760405163c429e07560e01b815260040160405180910390fd5b5050505050565b5f61038d838361100f565b5f6108ca85610d1a8787611058565b8585611101565b6060816001600160a01b031663582792376040518163ffffffff1660e01b81526004015f60405180830381865afa158015610d5e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261066b9190810190611653565b604080518082019091525f8152606060208201526040518060400160405280856001600160a01b031681526020018371524154455f4b45455045523a3a474155474560701b14610e13576040516001600160a01b038616602482015260440160408051601f198184030181529190526020810180516001600160e01b031663d48bfca760e01b179052610e61565b6040516001600160a01b0386166024820152600160448201819052606482015260840160408051601f198184030181529190526020810180516001600160e01b031663359cd5bf60e01b1790525b9052949350505050565b8151606090610e7b816001611713565b67ffffffffffffffff811115610e9357610e93611578565b604051908082528060200260200182016040528015610ed857816020015b604080518082019091525f815260606020820152815260200190600190039081610eb15790505b5091505f5b81811015610f2457848181518110610ef757610ef761158c565b6020026020010151838281518110610f1157610f1161158c565b6020908102919091010152600101610edd565b5082828281518110610f3857610f3861158c565b60200260200101819052505092915050565b5f610f5483610997565b71524154455f4b45455045523a3a474155474560701b03610ff4576001600160e01b0319821663d48bfca760e01b1480610f9e57506001600160e01b0319821663359cd5bf60e01b145b80610fb957506001600160e01b03198216633b54651d60e21b145b80610fed57506001600160e01b031982167f92eefe9b00000000000000000000000000000000000000000000000000000000145b905061066b565b506001600160e01b0319811663d48bfca760e01b1492915050565b5f81810361101e57508161066b565b61038d61102a846111ae565b611033846111ae565b604051602001611044929190611732565b6040516020818303038152906040526111e0565b6040517f4ceff70e00000000000000000000000000000000000000000000000000000000815260048101839052602481018290525f907f0000000000000000000000009700a405aff956f0baafc0a7ec57b71e656d5d9b6001600160a01b031690634ceff70e90604401602060405180830381865afa1580156110dd573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061038d91906115d0565b6040517f5ce8938f0000000000000000000000000000000000000000000000000000000081525f906001600160a01b037f0000000000000000000000009700a405aff956f0baafc0a7ec57b71e656d5d9b1690635ce8938f9061116e908890889088908890600401611789565b6020604051808303815f875af115801561118a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108ca91906115f2565b6040515f5b82811a156111c3576001016111b3565b808252602082018381525f82820152505060408101604052919050565b8051602181106111f75763ec92f9a35f526004601cfd5b9081015160209190910360031b1b90565b6001600160a01b038116811461121c575f80fd5b50565b5f805f60608486031215611231575f80fd5b833561123c81611208565b9250602084013561124c81611208565b9150604084013561125c81611208565b809150509250925092565b5f5b83811015611281578181015183820152602001611269565b50505f910152565b5f81518084526112a0816020860160208601611267565b601f01601f19169290920160200192915050565b5f82825180855260208086019550808260051b8401018186015f5b8481101561131a57858303601f19018952815180516001600160a01b03168452840151604085850181905261130681860183611289565b9a86019a94505050908301906001016112cf565b5090979650505050505050565b602081525f61038d60208301846112b4565b5f805f805f8060c0878903121561134e575f80fd5b863561135981611208565b9550602087013561136981611208565b9450604087013561137981611208565b9350606087013561138981611208565b9250608087013561139981611208565b915060a08701356113a981611208565b809150509295509295509295565b5f602082840312156113c7575f80fd5b813561038d81611208565b5f80604083850312156113e3575f80fd5b82356113ee81611208565b9150602083013567ffffffffffffffff811115611409575f80fd5b83016060818603121561141a575f80fd5b809150509250929050565b602081526001600160a01b0382511660208201525f602083015160408084015261145260608401826112b4565b949350505050565b5f805f6040848603121561146c575f80fd5b833561147781611208565b9250602084013567ffffffffffffffff80821115611493575f80fd5b818601915086601f8301126114a6575f80fd5b8135818111156114b4575f80fd5b8760208285010111156114c5575f80fd5b6020830194508093505050509250925092565b5f808335601e198436030181126114ed575f80fd5b83018035915067ffffffffffffffff821115611507575f80fd5b60200191503681900382131561151b575f80fd5b9250929050565b5f8060408385031215611533575f80fd5b823561153e81611208565b9150602083013561141a81611208565b5f806040838503121561155f575f80fd5b823561156a81611208565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b6001600160e01b031981358181169160048510156115c85780818660040360031b1b83161692505b505092915050565b5f602082840312156115e0575f80fd5b5051919050565b8051610a1281611208565b5f60208284031215611602575f80fd5b815161038d81611208565b5f6020828403121561161d575f80fd5b8151801515811461038d575f80fd5b5f808585111561163a575f80fd5b83861115611646575f80fd5b5050820193919092039150565b5f6020808385031215611664575f80fd5b825167ffffffffffffffff8082111561167b575f80fd5b818501915085601f83011261168e575f80fd5b8151818111156116a0576116a0611578565b8060051b604051601f19603f830116810181811085821117156116c5576116c5611578565b6040529182528482019250838101850191888311156116e2575f80fd5b938501935b82851015611707576116f8856115e7565b845293850193928501926116e7565b98975050505050505050565b8082018082111561066b57634e487b7160e01b5f52601160045260245ffd5b5f8351611743818460208801611267565b7f3a3a000000000000000000000000000000000000000000000000000000000000908301908152835161177d816002840160208801611267565b01600201949350505050565b848152836020820152608060408201525f6117a76080830185611289565b90508260608301529594505050505056fea164736f6c6343000817000a
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.