Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 25 from a total of 140 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Allow Public Con... | 22352760 | 296 days ago | IN | 0 ETH | 0.00017549 | ||||
| Submit Audit Rep... | 22347368 | 296 days ago | IN | 0 ETH | 0.00077956 | ||||
| Submit Audit Rep... | 22347362 | 296 days ago | IN | 0 ETH | 0.0007419 | ||||
| Submit Audit Rep... | 22347356 | 296 days ago | IN | 0 ETH | 0.00077054 | ||||
| Submit Audit Rep... | 22347349 | 296 days ago | IN | 0 ETH | 0.00071887 | ||||
| Submit Audit Rep... | 22347340 | 296 days ago | IN | 0 ETH | 0.00070636 | ||||
| Submit Audit Rep... | 22347328 | 296 days ago | IN | 0 ETH | 0.00074295 | ||||
| Submit Audit Rep... | 22347323 | 296 days ago | IN | 0 ETH | 0.00068456 | ||||
| Submit Audit Rep... | 22347314 | 296 days ago | IN | 0 ETH | 0.00062443 | ||||
| Submit Audit Rep... | 22347294 | 296 days ago | IN | 0 ETH | 0.00066044 | ||||
| Submit Audit Rep... | 22347286 | 296 days ago | IN | 0 ETH | 0.00067906 | ||||
| Submit Audit Rep... | 22347270 | 296 days ago | IN | 0 ETH | 0.00076685 | ||||
| Submit Audit Rep... | 22347261 | 296 days ago | IN | 0 ETH | 0.00084872 | ||||
| Submit Audit Rep... | 22347252 | 296 days ago | IN | 0 ETH | 0.00105765 | ||||
| Submit Audit Rep... | 22347228 | 296 days ago | IN | 0 ETH | 0.00108407 | ||||
| Submit Audit Rep... | 22347214 | 296 days ago | IN | 0 ETH | 0.00121144 | ||||
| Submit Audit Rep... | 22347184 | 296 days ago | IN | 0 ETH | 0.00113539 | ||||
| Submit Audit Rep... | 22347176 | 296 days ago | IN | 0 ETH | 0.00119291 | ||||
| Submit Audit Rep... | 22347166 | 296 days ago | IN | 0 ETH | 0.00113307 | ||||
| Submit Audit Rep... | 22347162 | 296 days ago | IN | 0 ETH | 0.00105177 | ||||
| Submit Audit Rep... | 22347157 | 296 days ago | IN | 0 ETH | 0.00074447 | ||||
| Submit Audit Rep... | 22347150 | 296 days ago | IN | 0 ETH | 0.00094633 | ||||
| Submit Audit Rep... | 22347146 | 296 days ago | IN | 0 ETH | 0.00090849 | ||||
| Submit Audit Rep... | 22347140 | 296 days ago | IN | 0 ETH | 0.00076223 | ||||
| Submit Audit Rep... | 22347135 | 296 days ago | IN | 0 ETH | 0.00078869 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60e06040 | 22352769 | 296 days ago | Contract Creation | 0 ETH | |||
| 0x61010060 | 22352769 | 296 days ago | Contract Creation | 0 ETH | |||
| 0x60e06040 | 22352769 | 296 days ago | Contract Creation | 0 ETH | |||
| 0x61012060 | 22352769 | 296 days ago | Contract Creation | 0 ETH | |||
| 0x61010060 | 22352769 | 296 days ago | Contract Creation | 0 ETH | |||
| 0x61010060 | 22352769 | 296 days ago | Contract Creation | 0 ETH | |||
| 0x60c06040 | 22352769 | 296 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 22352769 | 296 days ago | Contract Creation | 0 ETH | |||
| 0x61010060 | 22352769 | 296 days ago | Contract Creation | 0 ETH | |||
| 0x60806040 | 22352769 | 296 days ago | Contract Creation | 0 ETH | |||
| 0x6117f180 | 22296050 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x61160180 | 22296050 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x61152580 | 22296050 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x61124980 | 22296050 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x61150180 | 22296050 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x6111da80 | 22296050 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x61126d80 | 22296050 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x611f1580 | 22296050 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x6115ec80 | 22296049 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x61260980 | 22296049 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x61128580 | 22296049 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x611d4480 | 22296049 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x611d0e80 | 22296049 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x61142b80 | 22296049 | 304 days ago | Contract Creation | 0 ETH | |||
| 0x61173980 | 22296029 | 304 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
BytecodeRepository
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, 2025.
pragma solidity ^0.8.23;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {LibString} from "@solady/utils/LibString.sol";
import {SSTORE2} from "@solady/utils/SSTORE2.sol";
import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol";
import {SanityCheckTrait} from "@gearbox-protocol/core-v3/contracts/traits/SanityCheckTrait.sol";
import {EIP712Mainnet} from "../helpers/EIP712Mainnet.sol";
import {IBytecodeRepository} from "../interfaces/IBytecodeRepository.sol";
import {AuditReport, Bytecode, BytecodePointer} from "../interfaces/Types.sol";
import {AP_BYTECODE_REPOSITORY} from "../libraries/ContractLiterals.sol";
import {Domain} from "../libraries/Domain.sol";
import {ImmutableOwnableTrait} from "../traits/ImmutableOwnableTrait.sol";
/// @title Bytecode repository
contract BytecodeRepository is ImmutableOwnableTrait, SanityCheckTrait, IBytecodeRepository, EIP712Mainnet {
using EnumerableSet for EnumerableSet.AddressSet;
using EnumerableSet for EnumerableSet.Bytes32Set;
using EnumerableSet for EnumerableSet.UintSet;
using LibString for bytes32;
using LibString for string;
using LibString for uint256;
using Domain for bytes32;
/// @dev Internal struct with version info for a given contract type
struct VersionInfo {
address owner;
uint256 latest;
mapping(uint256 majorVersion => uint256) latestByMajor;
mapping(uint256 minorVersion => uint256) latestByMinor;
EnumerableSet.UintSet versionsSet;
}
/// @notice Contract version
uint256 public constant override version = 3_10;
/// @notice Contract type
bytes32 public constant override contractType = AP_BYTECODE_REPOSITORY;
/// @notice Bytecode typehash
bytes32 public constant override BYTECODE_TYPEHASH =
keccak256("Bytecode(bytes32 contractType,uint256 version,bytes initCode,address author,string source)");
/// @notice Audit report typehash
bytes32 public constant override AUDIT_REPORT_TYPEHASH =
keccak256("AuditReport(bytes32 bytecodeHash,address auditor,string reportUrl)");
/// @dev Mapping from `deployedContract` deployed from the repository to its bytecode hash
mapping(address deployedContract => bytes32) _deployedContractBytecodeHashes;
/// @dev Mapping from `bytecodeHash` to pointer to bytecode with given hash
mapping(bytes32 bytecodeHash => BytecodePointer) internal _bytecodeByHash;
/// @dev Mapping from `bytecodeHash` to its audit reports
mapping(bytes32 bytecodeHash => AuditReport[]) internal _auditReports;
/// @dev Mapping from `cType` to `ver` to allowed bytecode hash
mapping(bytes32 cType => mapping(uint256 ver => bytes32 bytecodeHash)) internal _allowedBytecodeHashes;
/// @dev Set of system domains
EnumerableSet.Bytes32Set internal _systemDomainsSet;
/// @dev Set of public domains
EnumerableSet.Bytes32Set internal _publicDomainsSet;
/// @dev Set of approved auditors
EnumerableSet.AddressSet internal _auditorsSet;
/// @dev Mapping from `auditor` to their name
mapping(address auditor => string) internal _auditorNames;
/// @dev Mapping from `initCodeHash` to whether it is forbidden
mapping(bytes32 initCodeHash => bool) internal _isInitCodeForbidden;
/// @dev Mapping from `token` to its specific postfix
mapping(address token => bytes32) internal _tokenSpecificPostfixes;
/// @dev Mapping from `cType` to its version info
mapping(bytes32 cType => VersionInfo) internal _versionInfo;
/// @notice Constructor
/// @param owner_ Owner of the bytecode repository
constructor(address owner_)
EIP712Mainnet(contractType.fromSmallString(), version.toString())
ImmutableOwnableTrait(owner_)
{}
// --------------- //
// EIP-712 GETTERS //
// --------------- //
/// @notice Returns the domain separator
function domainSeparatorV4() external view override returns (bytes32) {
return _domainSeparatorV4();
}
/// @notice Computes bytecode's struct hash
/// @dev `authorSignature` field is ignored
function computeBytecodeHash(Bytecode calldata bytecode) public pure override returns (bytes32) {
return keccak256(
abi.encode(
BYTECODE_TYPEHASH,
bytecode.contractType,
bytecode.version,
keccak256(bytecode.initCode),
bytecode.author,
keccak256(bytes(bytecode.source))
)
);
}
/// @notice Computes audit report's struct hash
/// @dev `signature` field is ignored
function computeAuditReportHash(bytes32 bytecodeHash, AuditReport calldata report)
public
pure
override
returns (bytes32)
{
return keccak256(
abi.encode(AUDIT_REPORT_TYPEHASH, bytecodeHash, report.auditor, keccak256(bytes(report.reportUrl)))
);
}
// ------------------- //
// DEPLOYING CONTRACTS //
// ------------------- //
/// @notice Whether `deployedContract` was deployed from the repository
function isDeployedFromRepository(address deployedContract) external view override returns (bool) {
return _deployedContractBytecodeHashes[deployedContract] != bytes32(0);
}
/// @notice Returns bytecode hash for `deployedContract` deployed from the repository
function getDeployedContractBytecodeHash(address deployedContract) external view override returns (bytes32) {
return _deployedContractBytecodeHashes[deployedContract];
}
/// @notice Computes the address at which a contract of a given type and version
/// with given constructor parameters and salt would be deployed
/// @dev Deployer's address is mixed with salt to prevent front-running using collisions
function computeAddress(bytes32 cType, uint256 ver, bytes memory constructorParams, bytes32 salt, address deployer)
external
view
override
returns (address)
{
bytes32 bytecodeHash = _allowedBytecodeHashes[cType][ver];
BytecodePointer storage bytecode = _bytecodeByHash[bytecodeHash];
bytes memory initCode = _readInitCode(bytecode.initCodePointers);
bytes32 uniqueSalt = keccak256(abi.encode(salt, deployer));
bytes memory bytecodeWithParams = abi.encodePacked(initCode, constructorParams);
return Create2.computeAddress(uniqueSalt, keccak256(bytecodeWithParams));
}
/// @notice Deploys a contract of a given type and version with given constructor parameters and salt.
/// Tries to transfer ownership over the deployed contract to the caller.
/// Bytecode must be allowed either as system or public contract, which, in turn, requires it
/// to be uploaded and have at least one signed report from approved auditor.
/// @dev Deployer's address is mixed with salt to prevent front-running using collisions
/// @dev Reverts if contract's init code is forbidden
/// @dev Reverts if contract was previously deployed at the same address
/// @dev Reverts if deployed contract's type or version does not match passed parameters
function deploy(bytes32 cType, uint256 ver, bytes memory constructorParams, bytes32 salt)
external
override
returns (address newContract)
{
bytes32 bytecodeHash = _allowedBytecodeHashes[cType][ver];
if (bytecodeHash == 0) revert BytecodeIsNotAllowedException(cType, ver);
BytecodePointer storage bytecode = _bytecodeByHash[bytecodeHash];
bytes memory initCode = _readInitCode(bytecode.initCodePointers);
_revertIfInitCodeIsForbidden(initCode);
bytes32 uniqueSalt = keccak256(abi.encode(salt, msg.sender));
bytes memory bytecodeWithParams = abi.encodePacked(initCode, constructorParams);
newContract = Create2.computeAddress(uniqueSalt, keccak256(bytecodeWithParams));
if (newContract.code.length != 0) revert ContractIsAlreadyDeployedException(newContract);
Create2.deploy(0, uniqueSalt, bytecodeWithParams);
if (IVersion(newContract).contractType() != cType || IVersion(newContract).version() != ver) {
revert InvalidBytecodeException(bytecodeHash);
}
_deployedContractBytecodeHashes[newContract] = bytecodeHash;
emit DeployContract(bytecodeHash, cType, ver, newContract, constructorParams);
try Ownable(newContract).transferOwnership(msg.sender) {} catch {}
}
// ------------------ //
// UPLOADING BYTECODE //
// ------------------ //
/// @notice Returns bytecode with `bytecodeHash`
/// @dev Reverts if bytecode is not uploaded
function getBytecode(bytes32 bytecodeHash) external view override returns (Bytecode memory) {
BytecodePointer memory bytecode = _bytecodeByHash[bytecodeHash];
if (bytecode.initCodePointers.length == 0) revert BytecodeIsNotUploadedException(bytecodeHash);
return Bytecode({
contractType: bytecode.contractType,
version: bytecode.version,
initCode: _readInitCode(bytecode.initCodePointers),
author: bytecode.author,
source: bytecode.source,
authorSignature: bytecode.authorSignature
});
}
/// @notice Whether bytecode with `bytecodeHash` is uploaded
function isBytecodeUploaded(bytes32 bytecodeHash) public view override returns (bool) {
return _bytecodeByHash[bytecodeHash].initCodePointers.length != 0;
}
/// @notice Uploads new contract bytecode to the repository.
/// Simply uploading the bytecode is not enough to deploy a contract with it, see `deploy` for details.
/// @dev Reverts if bytecode's contract type is invalid or version is less than `100` or greater than `999`
/// @dev Reverts if bytecode for given contract type and version is already allowed
/// @dev Reverts if author is zero address or if their signature is invalid
/// @dev Reverts if init code is empty
/// @dev On mainnet, only author of the bytecode can upload it
function uploadBytecode(Bytecode calldata bytecode) external override nonZeroAddress(bytecode.author) {
bytes32 bytecodeHash = computeBytecodeHash(bytecode);
if (isBytecodeUploaded(bytecodeHash)) return;
_validateContractType(bytecode.contractType);
_validateVersion(bytecode.contractType, bytecode.version);
if (_allowedBytecodeHashes[bytecode.contractType][bytecode.version] != 0) {
revert BytecodeIsAlreadyAllowedException(bytecode.contractType, bytecode.version);
}
if (block.chainid == 1 && msg.sender != bytecode.author) revert CallerIsNotBytecodeAuthorException(msg.sender);
address author = ECDSA.recover(_hashTypedDataV4(bytecodeHash), bytecode.authorSignature);
if (author != bytecode.author) revert InvalidAuthorSignatureException(author);
address[] memory initCodePointers = _writeInitCode(bytecode.initCode);
_bytecodeByHash[bytecodeHash] = BytecodePointer({
contractType: bytecode.contractType,
version: bytecode.version,
initCodePointers: initCodePointers,
author: bytecode.author,
source: bytecode.source,
authorSignature: bytecode.authorSignature
});
emit UploadBytecode(
bytecodeHash,
bytecode.contractType,
bytecode.version,
bytecode.author,
bytecode.source,
bytecode.authorSignature
);
}
/// @dev Stores contract's init code using `SSTORE2`, splitting it into chunks if needed
function _writeInitCode(bytes calldata initCode) internal returns (address[] memory initCodePointers) {
uint256 chunkSize = 24500; // small buffer to account for `SSTORE2` overhead
if (initCode.length == 0) revert InitCodeIsEmptyException();
uint256 len = (initCode.length - 1) / chunkSize + 1;
initCodePointers = new address[](len);
for (uint256 i; i < len; ++i) {
uint256 start = i * chunkSize;
uint256 end = start + chunkSize;
if (end > initCode.length) end = initCode.length;
initCodePointers[i] = SSTORE2.write(initCode[start:end]);
}
}
/// @dev Reads stored contract's init code using `SSTORE2`
function _readInitCode(address[] memory initCodePointers) internal view returns (bytes memory initCode) {
for (uint256 i; i < initCodePointers.length; ++i) {
initCode = bytes.concat(initCode, SSTORE2.read(initCodePointers[i]));
}
}
// ----------------- //
// AUDITING BYTECODE //
// ----------------- //
/// @notice Whether bytecode with `bytecodeHash` is signed at least by one approved auditor
function isBytecodeAudited(bytes32 bytecodeHash) public view override returns (bool) {
uint256 len = _auditReports[bytecodeHash].length;
for (uint256 i; i < len; ++i) {
AuditReport memory report = _auditReports[bytecodeHash][i];
if (isAuditor(report.auditor)) return true;
}
return false;
}
/// @notice Returns all audit reports for `bytecodeHash`
function getAuditReports(bytes32 bytecodeHash) external view override returns (AuditReport[] memory) {
return _auditReports[bytecodeHash];
}
/// @notice Returns audit report at `index` for `bytecodeHash`
function getAuditReport(bytes32 bytecodeHash, uint256 index) external view override returns (AuditReport memory) {
return _auditReports[bytecodeHash][index];
}
/// @notice Returns number of audit reports for `bytecodeHash`
function getNumAuditReports(bytes32 bytecodeHash) external view override returns (uint256) {
return _auditReports[bytecodeHash].length;
}
/// @notice Submits signed audit report for bytecode with `bytecodeHash`
/// @dev Reverts if bytecode is not uploaded
/// @dev Reverts if auditor is not approved, already signed bytecode, or their signature is invalid
function submitAuditReport(bytes32 bytecodeHash, AuditReport calldata auditReport) external override {
if (!isBytecodeUploaded(bytecodeHash)) revert BytecodeIsNotUploadedException(bytecodeHash);
if (!_auditorsSet.contains(auditReport.auditor)) revert AuditorIsNotApprovedException(auditReport.auditor);
bytes32 reportHash = computeAuditReportHash(bytecodeHash, auditReport);
address auditor = ECDSA.recover(_hashTypedDataV4(reportHash), auditReport.signature);
if (auditor != auditReport.auditor) revert InvalidAuditorSignatureException(auditor);
AuditReport[] storage reports = _auditReports[bytecodeHash];
uint256 len = reports.length;
for (uint256 i; i < len; ++i) {
if (keccak256(reports[i].signature) == keccak256(auditReport.signature)) {
revert BytecodeIsAlreadySignedByAuditorException(bytecodeHash, auditor);
}
}
reports.push(auditReport);
emit AuditBytecode(bytecodeHash, auditor, auditReport.reportUrl, auditReport.signature);
}
// ----------------- //
// ALLOWING BYTECODE //
// ----------------- //
/// @notice Returns the allowed bytecode hash for `cType` and `ver`
function getAllowedBytecodeHash(bytes32 cType, uint256 ver) external view override returns (bytes32) {
return _allowedBytecodeHashes[cType][ver];
}
/// @notice Returns the owner of `cType`
function getContractTypeOwner(bytes32 cType) external view override returns (address) {
return _versionInfo[cType].owner;
}
/// @notice Marks bytecode with `bytecodeHash` as allowed system contract.
/// Adds bytecode's domain to the list of system domains.
/// @dev Can only be called by the owner
/// @dev Reverts if bytecode is not uploaded or not audited
/// @dev Reverts if bytecode's contract type is in the list of public domains
/// @dev Reverts if bytecode with this contract type and version is already allowed
function allowSystemContract(bytes32 bytecodeHash) external override onlyOwner {
if (!isBytecodeUploaded(bytecodeHash)) revert BytecodeIsNotUploadedException(bytecodeHash);
if (!isBytecodeAudited(bytecodeHash)) revert BytecodeIsNotAuditedException(bytecodeHash);
BytecodePointer storage bytecode = _bytecodeByHash[bytecodeHash];
bytes32 cType = bytecode.contractType;
_addSystemDomain(cType.extractDomain());
_allowContract(bytecodeHash, cType, bytecode.version);
}
/// @notice Marks bytecode with `bytecodeHash` as allowed public contract.
/// Sets bytecode's author as contract type owner.
/// @dev Reverts if bytecode is not uploaded or not audited
/// @dev Reverts if bytecode's contract type is not in the list of public domains
/// @dev Reverts if bytecode's author is not contract type owner
/// @dev Reverts if bytecode with this contract type and version is already allowed
function allowPublicContract(bytes32 bytecodeHash) external override {
if (!isBytecodeUploaded(bytecodeHash)) revert BytecodeIsNotUploadedException(bytecodeHash);
if (!isBytecodeAudited(bytecodeHash)) revert BytecodeIsNotAuditedException(bytecodeHash);
BytecodePointer storage bytecode = _bytecodeByHash[bytecodeHash];
bytes32 cType = bytecode.contractType;
if (!isPublicDomain(cType.extractDomain())) revert ContractTypeIsNotInPublicDomainException(cType);
address author = bytecode.author;
address contractTypeOwner = _versionInfo[cType].owner;
if (contractTypeOwner == address(0)) {
_versionInfo[cType].owner = author;
emit SetContractTypeOwner(cType, author);
} else if (contractTypeOwner != author) {
revert AuthorIsNotContractTypeOwnerException(cType, author);
}
_allowContract(bytecodeHash, cType, bytecode.version);
}
/// @notice Forbids all previously allowed public contracts of a given type, removes type owner and version info.
/// Exists primarily to cleanup the repository after public domain squatting by a compromised auditor.
/// @dev Can only be called by the owner
function removePublicContractType(bytes32 cType) external override onlyOwner {
if (!isPublicDomain(cType.extractDomain())) return;
VersionInfo storage info = _versionInfo[cType];
if (info.owner != address(0)) {
info.owner = address(0);
emit RemoveContractTypeOwner(cType);
}
info.latest = 0;
uint256[] memory versions = info.versionsSet.values();
uint256 numVersions = versions.length;
for (uint256 i; i < numVersions; ++i) {
uint256 ver = versions[i];
info.versionsSet.remove(ver);
info.latestByMajor[_getMajorVersion(ver)] = 0;
info.latestByMinor[_getMinorVersion(ver)] = 0;
bytes32 bytecodeHash = _allowedBytecodeHashes[cType][ver];
_allowedBytecodeHashes[cType][ver] = bytes32(0);
emit ForbidContract(bytecodeHash, cType, ver);
}
}
/// @dev Allows bytecode with `bytecodeHash` for `cType` and `ver`, updates version info for `cType`
/// @dev Reverts if bytecode is already allowed
function _allowContract(bytes32 bytecodeHash, bytes32 cType, uint256 ver) internal {
if (_allowedBytecodeHashes[cType][ver] == bytecodeHash) return;
if (_allowedBytecodeHashes[cType][ver] != 0) revert BytecodeIsAlreadyAllowedException(cType, ver);
_allowedBytecodeHashes[cType][ver] = bytecodeHash;
emit AllowContract(bytecodeHash, cType, ver);
_updateVersionInfo(cType, ver);
}
// ------------------ //
// DOMAINS MANAGEMENT //
// ------------------ //
/// @notice Whether `domain` is in the list of system domains
function isSystemDomain(bytes32 domain) public view override returns (bool) {
return _systemDomainsSet.contains(domain);
}
/// @notice Returns list of all system domains
function getSystemDomains() external view override returns (bytes32[] memory) {
return _systemDomainsSet.values();
}
/// @notice Whether `domain` is in the list of public domains
function isPublicDomain(bytes32 domain) public view override returns (bool) {
return _publicDomainsSet.contains(domain);
}
/// @notice Returns list of all public domains
function getPublicDomains() external view override returns (bytes32[] memory) {
return _publicDomainsSet.values();
}
/// @notice Adds `domain` to the list of public domains
/// @dev Can only be called by the owner
/// @dev Reverts if `domain` is invalid or is already in the list of system domains
function addPublicDomain(bytes32 domain) external override onlyOwner {
_validateDomain(domain);
_addPublicDomain(domain);
}
/// @dev Adds `domain` to the list of public domains
/// @dev Reverts if `domain` is already in the list of system domains
function _addPublicDomain(bytes32 domain) internal {
if (isSystemDomain(domain)) revert DomainIsAlreadyMarkedAsSystemException(domain);
if (_publicDomainsSet.add(domain)) emit AddPublicDomain(domain);
}
/// @dev Adds `domain` to the list of system domains
/// @dev Reverts if `domain` is already in the list of public domains
function _addSystemDomain(bytes32 domain) internal {
if (isPublicDomain(domain)) revert DomainIsAlreadyMarkedAsPublicException(domain);
if (_systemDomainsSet.add(domain)) emit AddSystemDomain(domain);
}
// ------------------- //
// AUDITORS MANAGEMENT //
// ------------------- //
/// @notice Whether `auditor` is an approved auditor
function isAuditor(address auditor) public view override returns (bool) {
return _auditorsSet.contains(auditor);
}
/// @notice Returns list of all approved auditors
function getAuditors() external view override returns (address[] memory) {
return _auditorsSet.values();
}
/// @notice Returns `auditor`'s name
function getAuditorName(address auditor) external view override returns (string memory) {
return _auditorNames[auditor];
}
/// @notice Adds `auditor` to the list of approved auditors
/// @dev Can only be called by the owner
/// @dev Reverts if `auditor` is zero address
function addAuditor(address auditor, string memory name) external override onlyOwner nonZeroAddress(auditor) {
if (!_auditorsSet.add(auditor)) return;
_auditorNames[auditor] = name;
emit AddAuditor(auditor, name);
}
/// @notice Removes `auditor` from the list of approved auditors
/// @dev Can only be called by the owner
function removeAuditor(address auditor) external override onlyOwner {
if (!_auditorsSet.remove(auditor)) return;
delete _auditorNames[auditor];
emit RemoveAuditor(auditor);
}
// -------------------- //
// FORBIDDING INIT CODE //
// -------------------- //
/// @notice Whether init code with `initCodeHash` is forbidden
function isInitCodeForbidden(bytes32 initCodeHash) external view override returns (bool) {
return _isInitCodeForbidden[initCodeHash];
}
/// @notice Permanently marks init code with `initCodeHash` as forbidden
/// @dev Can only be called by the owner
function forbidInitCode(bytes32 initCodeHash) external override onlyOwner {
if (_isInitCodeForbidden[initCodeHash]) return;
_isInitCodeForbidden[initCodeHash] = true;
emit ForbidInitCode(initCodeHash);
}
/// @dev Reverts if `initCode` is forbidden
function _revertIfInitCodeIsForbidden(bytes memory initCode) internal view {
bytes32 initCodeHash = keccak256(initCode);
if (_isInitCodeForbidden[initCodeHash]) revert InitCodeIsForbiddenException(initCodeHash);
}
// ------------------------ //
// TOKENS WITH CUSTOM LOGIC //
// ------------------------ //
/// @notice Returns `token`'s specific postfix, if any
function getTokenSpecificPostfix(address token) external view override returns (bytes32) {
return _tokenSpecificPostfixes[token];
}
/// @notice Sets `token`'s specific `postfix`
/// @dev Can only be called by the owner
/// @dev Reverts if `postfix` is invalid
function setTokenSpecificPostfix(address token, bytes32 postfix) external override onlyOwner {
_validatePostfix(postfix);
if (_tokenSpecificPostfixes[token] == postfix) return;
_tokenSpecificPostfixes[token] = postfix;
emit SetTokenSpecificPostfix(token, postfix);
}
// --------------- //
// VERSION CONTROL //
// --------------- //
/// @notice Returns all versions for `cType`
function getVersions(bytes32 cType) external view override returns (uint256[] memory) {
return _versionInfo[cType].versionsSet.values();
}
/// @notice Returns the latest known bytecode version for given `cType`
/// @dev Reverts if `cType` has no bytecode entries
function getLatestVersion(bytes32 cType) external view override returns (uint256 ver) {
ver = _versionInfo[cType].latest;
if (ver == 0) revert VersionNotFoundException(cType);
}
/// @notice Returns the latest known version for given `cType` with matching `majorVersion`
/// @dev Reverts if `majorVersion` is less than `100` or greater than `999`
/// @dev Reverts if `cType` has no bytecode entries with matching `majorVersion`
function getLatestMinorVersion(bytes32 cType, uint256 majorVersion) external view override returns (uint256 ver) {
_validateVersion(cType, majorVersion);
ver = _versionInfo[cType].latestByMajor[_getMajorVersion(majorVersion)];
if (ver == 0) revert VersionNotFoundException(cType);
}
/// @notice Returns the latest known version for given `cType` with matching `minorVersion`
/// @dev Reverts if `minorVersion` is less than `100` or greater than `999`
/// @dev Reverts if `cType` has no bytecode entries with matching `minorVersion`
function getLatestPatchVersion(bytes32 cType, uint256 minorVersion) external view override returns (uint256 ver) {
_validateVersion(cType, minorVersion);
ver = _versionInfo[cType].latestByMinor[_getMinorVersion(minorVersion)];
if (ver == 0) revert VersionNotFoundException(cType);
}
/// @dev Updates version info for `cType` based on `ver`
function _updateVersionInfo(bytes32 cType, uint256 ver) internal {
VersionInfo storage info = _versionInfo[cType];
if (ver > info.latest) info.latest = ver;
uint256 majorVersion = _getMajorVersion(ver);
if (ver > info.latestByMajor[majorVersion]) info.latestByMajor[majorVersion] = ver;
uint256 minorVersion = _getMinorVersion(ver);
if (ver > info.latestByMinor[minorVersion]) info.latestByMinor[minorVersion] = ver;
info.versionsSet.add(ver);
}
/// @dev Returns the major version of a given version
function _getMajorVersion(uint256 ver) internal pure returns (uint256) {
return ver - ver % 100;
}
/// @dev Returns the minor version of a given version
function _getMinorVersion(uint256 ver) internal pure returns (uint256) {
return ver - ver % 10;
}
/// @dev Reverts if `cType` is invalid
function _validateContractType(bytes32 cType) internal pure {
if (!cType.isValidContractType()) revert InvalidContractTypeException(cType);
}
/// @dev Reverts if `domain` is invalid
function _validateDomain(bytes32 domain) internal pure {
if (!domain.isValidDomain()) revert InvalidDomainException(domain);
}
/// @dev Reverts if `postfix` is invalid
function _validatePostfix(bytes32 postfix) internal pure {
if (!postfix.isValidPostfix()) revert InvalidPostfixException(postfix);
}
/// @dev Reverts if `ver` is less than `100` or greater than `999`
function _validateVersion(bytes32 cType, uint256 ver) internal pure {
if (ver < 100 || ver > 999) revert InvalidVersionException(cType, ver);
}
}// 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
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Create2.sol)
pragma solidity ^0.8.0;
/**
* @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
* `CREATE2` can be used to compute in advance the address where a smart
* contract will be deployed, which allows for interesting new mechanisms known
* as 'counterfactual interactions'.
*
* See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
* information.
*/
library Create2 {
/**
* @dev Deploys a contract using `CREATE2`. The address where the contract
* will be deployed can be known in advance via {computeAddress}.
*
* The bytecode for a contract can be obtained from Solidity with
* `type(contractName).creationCode`.
*
* Requirements:
*
* - `bytecode` must not be empty.
* - `salt` must have not been used for `bytecode` already.
* - the factory must have a balance of at least `amount`.
* - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
*/
function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
require(address(this).balance >= amount, "Create2: insufficient balance");
require(bytecode.length != 0, "Create2: bytecode length is zero");
/// @solidity memory-safe-assembly
assembly {
addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
}
require(addr != address(0), "Create2: Failed on deploy");
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
* `bytecodeHash` or `salt` will result in a new destination address.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
return computeAddress(salt, bytecodeHash, address(this));
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
* `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40) // Get free memory pointer
// | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |
// |-------------------|---------------------------------------------------------------------------|
// | bytecodeHash | CCCCCCCCCCCCC...CC |
// | salt | BBBBBBBBBBBBB...BB |
// | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |
// | 0xFF | FF |
// |-------------------|---------------------------------------------------------------------------|
// | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
// | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
mstore(add(ptr, 0x40), bytecodeHash)
mstore(add(ptr, 0x20), salt)
mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
mstore8(start, 0xff)
addr := keccak256(start, 85)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// 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
pragma solidity ^0.8.4;
/// @notice Read and write to persistent storage at a fraction of the cost.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SSTORE2.sol)
/// @author Saw-mon-and-Natalie (https://github.com/Saw-mon-and-Natalie)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol)
/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol)
library SSTORE2 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev We skip the first byte as it's a STOP opcode,
/// which ensures the contract can't be called.
uint256 internal constant DATA_OFFSET = 1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Unable to deploy the storage contract.
error DeploymentFailed();
/// @dev The storage contract address is invalid.
error InvalidPointer();
/// @dev Attempt to read outside of the storage contract's bytecode bounds.
error ReadOutOfBounds();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* WRITE LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Writes `data` into the bytecode of a storage contract and returns its address.
function write(bytes memory data) internal returns (address pointer) {
/// @solidity memory-safe-assembly
assembly {
let originalDataLength := mload(data)
// Add 1 to data size since we are prefixing it with a STOP opcode.
let dataSize := add(originalDataLength, DATA_OFFSET)
/**
* ------------------------------------------------------------------------------+
* Opcode | Mnemonic | Stack | Memory |
* ------------------------------------------------------------------------------|
* 61 dataSize | PUSH2 dataSize | dataSize | |
* 80 | DUP1 | dataSize dataSize | |
* 60 0xa | PUSH1 0xa | 0xa dataSize dataSize | |
* 3D | RETURNDATASIZE | 0 0xa dataSize dataSize | |
* 39 | CODECOPY | dataSize | [0..dataSize): code |
* 3D | RETURNDATASIZE | 0 dataSize | [0..dataSize): code |
* F3 | RETURN | | [0..dataSize): code |
* 00 | STOP | | |
* ------------------------------------------------------------------------------+
* @dev Prefix the bytecode with a STOP opcode to ensure it cannot be called.
* Also PUSH2 is used since max contract size cap is 24,576 bytes which is less than 2 ** 16.
*/
mstore(
// Do a out-of-gas revert if `dataSize` is more than 2 bytes.
// The actual EVM limit may be smaller and may change over time.
add(data, gt(dataSize, 0xffff)),
// Left shift `dataSize` by 64 so that it lines up with the 0000 after PUSH2.
or(0xfd61000080600a3d393df300, shl(0x40, dataSize))
)
// Deploy a new contract with the generated creation code.
pointer := create(0, add(data, 0x15), add(dataSize, 0xa))
// If `pointer` is zero, revert.
if iszero(pointer) {
// Store the function selector of `DeploymentFailed()`.
mstore(0x00, 0x30116425)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Restore original length of the variable size `data`.
mstore(data, originalDataLength)
}
}
/// @dev Writes `data` into the bytecode of a storage contract with `salt`
/// and returns its deterministic address.
function writeDeterministic(bytes memory data, bytes32 salt)
internal
returns (address pointer)
{
/// @solidity memory-safe-assembly
assembly {
let originalDataLength := mload(data)
let dataSize := add(originalDataLength, DATA_OFFSET)
mstore(
// Do a out-of-gas revert if `dataSize` is more than 2 bytes.
// The actual EVM limit may be smaller and may change over time.
add(data, gt(dataSize, 0xffff)),
// Left shift `dataSize` by 64 so that it lines up with the 0000 after PUSH2.
or(0xfd61000080600a3d393df300, shl(0x40, dataSize))
)
// Deploy a new contract with the generated creation code.
pointer := create2(0, add(data, 0x15), add(dataSize, 0xa), salt)
// If `pointer` is zero, revert.
if iszero(pointer) {
// Store the function selector of `DeploymentFailed()`.
mstore(0x00, 0x30116425)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Restore original length of the variable size `data`.
mstore(data, originalDataLength)
}
}
/// @dev Returns the initialization code hash of the storage contract for `data`.
/// Used for mining vanity addresses with create2crunch.
function initCodeHash(bytes memory data) internal pure returns (bytes32 hash) {
/// @solidity memory-safe-assembly
assembly {
let originalDataLength := mload(data)
let dataSize := add(originalDataLength, DATA_OFFSET)
// Do a out-of-gas revert if `dataSize` is more than 2 bytes.
// The actual EVM limit may be smaller and may change over time.
returndatacopy(returndatasize(), returndatasize(), shr(16, dataSize))
mstore(data, or(0x61000080600a3d393df300, shl(0x40, dataSize)))
hash := keccak256(add(data, 0x15), add(dataSize, 0xa))
// Restore original length of the variable size `data`.
mstore(data, originalDataLength)
}
}
/// @dev Returns the address of the storage contract for `data`
/// deployed with `salt` by `deployer`.
/// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
function predictDeterministicAddress(bytes memory data, bytes32 salt, address deployer)
internal
pure
returns (address predicted)
{
bytes32 hash = initCodeHash(data);
/// @solidity memory-safe-assembly
assembly {
// Compute and store the bytecode hash.
mstore8(0x00, 0xff) // Write the prefix.
mstore(0x35, hash)
mstore(0x01, shl(96, deployer))
mstore(0x15, salt)
predicted := keccak256(0x00, 0x55)
// Restore the part of the free memory pointer that has been overwritten.
mstore(0x35, 0)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* READ LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns all the `data` from the bytecode of the storage contract at `pointer`.
function read(address pointer) internal view returns (bytes memory data) {
/// @solidity memory-safe-assembly
assembly {
let pointerCodesize := extcodesize(pointer)
if iszero(pointerCodesize) {
// Store the function selector of `InvalidPointer()`.
mstore(0x00, 0x11052bb4)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Offset all indices by 1 to skip the STOP opcode.
let size := sub(pointerCodesize, DATA_OFFSET)
// Get the pointer to the free memory and allocate
// enough 32-byte words for the data and the length of the data,
// then copy the code to the allocated memory.
// Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
data := mload(0x40)
mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
mstore(data, size)
mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot.
extcodecopy(pointer, add(data, 0x20), DATA_OFFSET, size)
}
}
/// @dev Returns the `data` from the bytecode of the storage contract at `pointer`,
/// from the byte at `start`, to the end of the data stored.
function read(address pointer, uint256 start) internal view returns (bytes memory data) {
/// @solidity memory-safe-assembly
assembly {
let pointerCodesize := extcodesize(pointer)
if iszero(pointerCodesize) {
// Store the function selector of `InvalidPointer()`.
mstore(0x00, 0x11052bb4)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// If `!(pointer.code.size > start)`, reverts.
// This also handles the case where `start + DATA_OFFSET` overflows.
if iszero(gt(pointerCodesize, start)) {
// Store the function selector of `ReadOutOfBounds()`.
mstore(0x00, 0x84eb0dd1)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
let size := sub(pointerCodesize, add(start, DATA_OFFSET))
// Get the pointer to the free memory and allocate
// enough 32-byte words for the data and the length of the data,
// then copy the code to the allocated memory.
// Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
data := mload(0x40)
mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
mstore(data, size)
mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot.
extcodecopy(pointer, add(data, 0x20), add(start, DATA_OFFSET), size)
}
}
/// @dev Returns the `data` from the bytecode of the storage contract at `pointer`,
/// from the byte at `start`, to the byte at `end` (exclusive) of the data stored.
function read(address pointer, uint256 start, uint256 end)
internal
view
returns (bytes memory data)
{
/// @solidity memory-safe-assembly
assembly {
let pointerCodesize := extcodesize(pointer)
if iszero(pointerCodesize) {
// Store the function selector of `InvalidPointer()`.
mstore(0x00, 0x11052bb4)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// If `!(pointer.code.size > end) || (start > end)`, revert.
// This also handles the cases where
// `end + DATA_OFFSET` or `start + DATA_OFFSET` overflows.
if iszero(
and(
gt(pointerCodesize, end), // Within bounds.
iszero(gt(start, end)) // Valid range.
)
) {
// Store the function selector of `ReadOutOfBounds()`.
mstore(0x00, 0x84eb0dd1)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
let size := sub(end, start)
// Get the pointer to the free memory and allocate
// enough 32-byte words for the data and the length of the data,
// then copy the code to the allocated memory.
// Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
data := mload(0x40)
mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
mstore(data, size)
mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot.
extcodecopy(pointer, add(data, 0x20), add(start, DATA_OFFSET), size)
}
}
}// 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: BUSL-1.1
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;
import {ZeroAddressException} from "../interfaces/IExceptions.sol";
/// @title Sanity check trait
abstract contract SanityCheckTrait {
/// @dev Ensures that passed address is non-zero
modifier nonZeroAddress(address addr) {
_revertIfZeroAddress(addr);
_;
}
/// @dev Reverts if address is zero
function _revertIfZeroAddress(address addr) private pure {
if (addr == address(0)) revert ZeroAddressException();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.8;
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {ShortStrings, ShortString} from "@openzeppelin/contracts/utils/ShortStrings.sol";
import {IERC5267} from "@openzeppelin/contracts/interfaces/IERC5267.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*
* _Available since v3.4._
*
* @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
*/
abstract contract EIP712Mainnet is IERC5267 {
using ShortStrings for *;
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
bytes32 private immutable _cachedDomainSeparator;
uint256 private constant _HARDCODED_CHAIN_ID = 1;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
string private _nameFallback;
string private _versionFallback;
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
/**
* @dev Returns the domain separator.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, _HARDCODED_CHAIN_ID, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev See {EIP-5267}.
*
* _Available since v4.9._
*/
function eip712Domain()
public
view
virtual
override
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f", // 01111
_name.toStringWithFallback(_nameFallback),
_version.toStringWithFallback(_versionFallback),
_HARDCODED_CHAIN_ID,
address(this),
bytes32(0),
new uint256[](0)
);
}
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2025.
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,
bytes constructorParams
);
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 DomainIsAlreadyMarkedAsPublicException(bytes32 domain);
error DomainIsAlreadyMarkedAsSystemException(bytes32 domain);
error InitCodeIsEmptyException();
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 InvalidPostfixException(bytes32 postfix);
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, AuditReport calldata report)
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: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2025.
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[] initCodePointers;
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, 2025. 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 = "GLOBAL::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, 2025.
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: BUSL-1.1
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2025.
pragma solidity ^0.8.23;
import {IImmutableOwnableTrait} from "../interfaces/base/IImmutableOwnableTrait.sol";
abstract contract ImmutableOwnableTrait is IImmutableOwnableTrait {
address public immutable override owner;
modifier onlyOwner() {
if (msg.sender != owner) revert CallerIsNotOwnerException(msg.sender);
_;
}
constructor(address owner_) {
owner = owner_;
}
}// 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
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024. pragma solidity ^0.8.17; // ------- // // GENERAL // // ------- // /// @notice Thrown on attempting to set an important address to zero address error ZeroAddressException(); /// @notice Thrown when attempting to pass a zero amount to a funding-related operation error AmountCantBeZeroException(); /// @notice Thrown on incorrect input parameter error IncorrectParameterException(); /// @notice Thrown when balance is insufficient to perform an operation error InsufficientBalanceException(); /// @notice Thrown if parameter is out of range error ValueOutOfRangeException(); /// @notice Thrown when trying to send ETH to a contract that is not allowed to receive ETH directly error ReceiveIsNotAllowedException(); /// @notice Thrown on attempting to set an EOA as an important contract in the system error AddressIsNotContractException(address); /// @notice Thrown on attempting to receive a token that is not a collateral token or was forbidden error TokenNotAllowedException(); /// @notice Thrown on attempting to add a token that is already in a collateral list error TokenAlreadyAddedException(); /// @notice Thrown when attempting to use quota-related logic for a token that is not quoted in quota keeper error TokenIsNotQuotedException(); /// @notice Thrown on attempting to interact with an address that is not a valid target contract error TargetContractNotAllowedException(); /// @notice Thrown if function is not implemented error NotImplementedException(); // ------------------ // // CONTRACTS REGISTER // // ------------------ // /// @notice Thrown when an address is expected to be a registered credit manager, but is not error RegisteredCreditManagerOnlyException(); /// @notice Thrown when an address is expected to be a registered pool, but is not error RegisteredPoolOnlyException(); // ---------------- // // ADDRESS PROVIDER // // ---------------- // /// @notice Reverts if address key isn't found in address provider error AddressNotFoundException(); // ----------------- // // POOL, PQK, GAUGES // // ----------------- // /// @notice Thrown by pool-adjacent contracts when a credit manager being connected has a wrong pool address error IncompatibleCreditManagerException(); /// @notice Thrown when attempting to set an incompatible successor staking contract error IncompatibleSuccessorException(); /// @notice Thrown when attempting to vote in a non-approved contract error VotingContractNotAllowedException(); /// @notice Thrown when attempting to unvote more votes than there are error InsufficientVotesException(); /// @notice Thrown when attempting to borrow more than the second point on a two-point curve error BorrowingMoreThanU2ForbiddenException(); /// @notice Thrown when a credit manager attempts to borrow more than its limit in the current block, or in general error CreditManagerCantBorrowException(); /// @notice Thrown when attempting to connect a quota keeper to an incompatible pool error IncompatiblePoolQuotaKeeperException(); /// @notice Thrown when attempting to connect a gauge to an incompatible pool quota keeper error IncompatibleGaugeException(); /// @notice Thrown when the quota is outside of min/max bounds error QuotaIsOutOfBoundsException(); // -------------- // // CREDIT MANAGER // // -------------- // /// @notice Thrown on failing a full collateral check after multicall error NotEnoughCollateralException(); /// @notice Thrown if an attempt to approve a collateral token to adapter's target contract fails error AllowanceFailedException(); /// @notice Thrown on attempting to perform an action for a credit account that does not exist error CreditAccountDoesNotExistException(); /// @notice Thrown on configurator attempting to add more than 255 collateral tokens error TooManyTokensException(); /// @notice Thrown if more than the maximum number of tokens were enabled on a credit account error TooManyEnabledTokensException(); /// @notice Thrown when attempting to execute a protocol interaction without active credit account set error ActiveCreditAccountNotSetException(); /// @notice Thrown when trying to update credit account's debt more than once in the same block error DebtUpdatedTwiceInOneBlockException(); /// @notice Thrown when trying to repay all debt while having active quotas error DebtToZeroWithActiveQuotasException(); /// @notice Thrown when a zero-debt account attempts to update quota error UpdateQuotaOnZeroDebtAccountException(); /// @notice Thrown when attempting to close an account with non-zero debt error CloseAccountWithNonZeroDebtException(); /// @notice Thrown when value of funds remaining on the account after liquidation is insufficient error InsufficientRemainingFundsException(); /// @notice Thrown when Credit Facade tries to write over a non-zero active Credit Account error ActiveCreditAccountOverridenException(); // ------------------- // // CREDIT CONFIGURATOR // // ------------------- // /// @notice Thrown on attempting to use a non-ERC20 contract or an EOA as a token error IncorrectTokenContractException(); /// @notice Thrown if the newly set LT if zero or greater than the underlying's LT error IncorrectLiquidationThresholdException(); /// @notice Thrown if borrowing limits are incorrect: minLimit > maxLimit or maxLimit > blockLimit error IncorrectLimitsException(); /// @notice Thrown if the new expiration date is less than the current expiration date or current timestamp error IncorrectExpirationDateException(); /// @notice Thrown if a contract returns a wrong credit manager or reverts when trying to retrieve it error IncompatibleContractException(); /// @notice Thrown if attempting to forbid an adapter that is not registered in the credit manager error AdapterIsNotRegisteredException(); /// @notice Thrown if new credit configurator's set of allowed adapters differs from the current one error IncorrectAdaptersSetException(); /// @notice Thrown if attempting to schedule a token's LT ramping that is too short in duration error RampDurationTooShortException(); /// @notice Thrown if attempting to set liquidation fees such that the sum of premium and fee changes error InconsistentLiquidationFeesException(); /// @notice Thrown if attempting to set expired liquidation fees such that the sum of premium and fee changes error InconsistentExpiredLiquidationFeesException(); // ------------- // // CREDIT FACADE // // ------------- // /// @notice Thrown when attempting to perform an action that is forbidden in whitelisted mode error ForbiddenInWhitelistedModeException(); /// @notice Thrown if credit facade is not expirable, and attempted aciton requires expirability error NotAllowedWhenNotExpirableException(); /// @notice Thrown if a selector that doesn't match any allowed function is passed to the credit facade in a multicall error UnknownMethodException(bytes4 selector); /// @notice Thrown if a liquidator tries to liquidate an account with a health factor above 1 error CreditAccountNotLiquidatableException(); /// @notice Thrown if a liquidator tries to liquidate an account with loss but violates the loss policy error CreditAccountNotLiquidatableWithLossException(); /// @notice Thrown if too much new debt was taken within a single block error BorrowedBlockLimitException(); /// @notice Thrown if the new debt principal for a credit account falls outside of borrowing limits error BorrowAmountOutOfLimitsException(); /// @notice Thrown if a user attempts to open an account via an expired credit facade error NotAllowedAfterExpirationException(); /// @notice Thrown if expected balances are attempted to be set twice without performing a slippage check error ExpectedBalancesAlreadySetException(); /// @notice Thrown if attempting to perform a slippage check when excepted balances are not set error ExpectedBalancesNotSetException(); /// @notice Thrown if balance of at least one token is less than expected during a slippage check error BalanceLessThanExpectedException(address token); /// @notice Thrown when trying to perform an action that is forbidden when credit account has enabled forbidden tokens error ForbiddenTokensException(uint256 forbiddenTokensMask); /// @notice Thrown when forbidden token quota is increased during the multicall error ForbiddenTokenQuotaIncreasedException(address token); /// @notice Thrown when enabled forbidden token balance is increased during the multicall error ForbiddenTokenBalanceIncreasedException(address token); /// @notice Thrown when the remaining token balance is increased during the liquidation error RemainingTokenBalanceIncreasedException(address token); /// @notice Thrown if `botMulticall` is called by an address that is not approved by account owner or is forbidden error NotApprovedBotException(address bot); /// @notice Thrown when attempting to perform a multicall action with no permission for it error NoPermissionException(uint256 permission); /// @notice Thrown when attempting to give a bot unexpected permissions error UnexpectedPermissionsException(uint256 permissions); /// @notice Thrown when a custom HF parameter lower than 10000 is passed into the full collateral check error CustomHealthFactorTooLowException(); /// @notice Thrown when submitted collateral hint is not a valid token mask error InvalidCollateralHintException(uint256 mask); /// @notice Thrown when trying to seize underlying token during partial liquidation error UnderlyingIsNotLiquidatableException(); /// @notice Thrown when amount of collateral seized during partial liquidation is less than required error SeizedLessThanRequiredException(uint256 seizedAmount); // ------ // // ACCESS // // ------ // /// @notice Thrown on attempting to call an access restricted function not as credit account owner error CallerNotCreditAccountOwnerException(); /// @notice Thrown on attempting to call an access restricted function not as configurator error CallerNotConfiguratorException(); /// @notice Thrown on attempting to call an access-restructed function not as account factory error CallerNotAccountFactoryException(); /// @notice Thrown on attempting to call an access restricted function not as credit manager error CallerNotCreditManagerException(); /// @notice Thrown on attempting to call an access restricted function not as credit facade error CallerNotCreditFacadeException(); /// @notice Thrown on attempting to pause a contract without pausable admin rights error CallerNotPausableAdminException(); /// @notice Thrown on attempting to unpause a contract without unpausable admin rights error CallerNotUnpausableAdminException(); /// @notice Thrown on attempting to call an access restricted function not as gauge error CallerNotGaugeException(); /// @notice Thrown on attempting to call an access restricted function not as quota keeper error CallerNotPoolQuotaKeeperException(); /// @notice Thrown on attempting to call an access restricted function not as voter error CallerNotVoterException(); /// @notice Thrown on attempting to call an access restricted function not as allowed adapter error CallerNotAdapterException(); /// @notice Thrown on attempting to call an access restricted function not as migrator error CallerNotMigratorException(); /// @notice Thrown when an address that is not the designated executor attempts to execute a transaction error CallerNotExecutorException(); /// @notice Thrown on attempting to call an access restricted function not as veto admin error CallerNotVetoAdminException(); // -------- // // BOT LIST // // -------- // /// @notice Thrown when attempting to set non-zero permissions for a forbidden bot error InvalidBotException(); /// @notice Thrown when attempting to set permissions for a bot that don't meet its requirements error IncorrectBotPermissionsException(); /// @notice Thrown when attempting to set non-zero permissions for too many bots error TooManyActiveBotsException(); // --------------- // // ACCOUNT FACTORY // // --------------- // /// @notice Thrown when trying to deploy second master credit account for a credit manager error MasterCreditAccountAlreadyDeployedException(); /// @notice Thrown when trying to rescue funds from a credit account that is currently in use error CreditAccountIsInUseException(); // ------------ // // PRICE ORACLE // // ------------ // /// @notice Thrown on attempting to set a token price feed to an address that is not a correct price feed error IncorrectPriceFeedException(); /// @notice Thrown on attempting to interact with a price feed for a token not added to the price oracle error PriceFeedDoesNotExistException(); /// @notice Thrown when trying to apply an on-demand price update to a non-updatable price feed error PriceFeedIsNotUpdatableException(); /// @notice Thrown when price feed returns incorrect price for a token error IncorrectPriceException(); /// @notice Thrown when token's price feed becomes stale error StalePriceException();
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.8;
import "./StorageSlot.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStrings {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(_FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.0;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2025.
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) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}{
"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/",
"@solady/=lib/@solady/src/",
"@redstone-finance/=node_modules/@redstone-finance/",
"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":"owner_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"auditor","type":"address"}],"name":"AuditorIsNotApprovedException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"contractType","type":"bytes32"},{"internalType":"address","name":"author","type":"address"}],"name":"AuthorIsNotContractTypeOwnerException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"contractType","type":"bytes32"},{"internalType":"uint256","name":"version","type":"uint256"}],"name":"BytecodeIsAlreadyAllowedException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"},{"internalType":"address","name":"auditor","type":"address"}],"name":"BytecodeIsAlreadySignedByAuditorException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"contractType","type":"bytes32"},{"internalType":"uint256","name":"version","type":"uint256"}],"name":"BytecodeIsNotAllowedException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"}],"name":"BytecodeIsNotAuditedException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"}],"name":"BytecodeIsNotUploadedException","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotBytecodeAuthorException","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotOwnerException","type":"error"},{"inputs":[{"internalType":"address","name":"deployedContract","type":"address"}],"name":"ContractIsAlreadyDeployedException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"contractType","type":"bytes32"}],"name":"ContractTypeIsNotInPublicDomainException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"domain","type":"bytes32"}],"name":"DomainIsAlreadyMarkedAsPublicException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"domain","type":"bytes32"}],"name":"DomainIsAlreadyMarkedAsSystemException","type":"error"},{"inputs":[],"name":"InitCodeIsEmptyException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"initCodeHash","type":"bytes32"}],"name":"InitCodeIsForbiddenException","type":"error"},{"inputs":[{"internalType":"address","name":"auditor","type":"address"}],"name":"InvalidAuditorSignatureException","type":"error"},{"inputs":[{"internalType":"address","name":"author","type":"address"}],"name":"InvalidAuthorSignatureException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"}],"name":"InvalidBytecodeException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"contractType","type":"bytes32"}],"name":"InvalidContractTypeException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"domain","type":"bytes32"}],"name":"InvalidDomainException","type":"error"},{"inputs":[{"internalType":"bytes32","name":"postfix","type":"bytes32"}],"name":"InvalidPostfixException","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[{"internalType":"bytes32","name":"contractType","type":"bytes32"},{"internalType":"uint256","name":"version","type":"uint256"}],"name":"InvalidVersionException","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"bytes32","name":"contractType","type":"bytes32"}],"name":"VersionNotFoundException","type":"error"},{"inputs":[],"name":"ZeroAddressException","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"auditor","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"AddAuditor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"domain","type":"bytes32"}],"name":"AddPublicDomain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"domain","type":"bytes32"}],"name":"AddSystemDomain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"contractType","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"version","type":"uint256"}],"name":"AllowContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"auditor","type":"address"},{"indexed":false,"internalType":"string","name":"reportUrl","type":"string"},{"indexed":false,"internalType":"bytes","name":"signature","type":"bytes"}],"name":"AuditBytecode","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"contractType","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"version","type":"uint256"},{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"bytes","name":"constructorParams","type":"bytes"}],"name":"DeployContract","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"contractType","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ForbidContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"initCodeHash","type":"bytes32"}],"name":"ForbidInitCode","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"auditor","type":"address"}],"name":"RemoveAuditor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"contractType","type":"bytes32"}],"name":"RemoveContractTypeOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"contractType","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"SetContractTypeOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"bytes32","name":"postfix","type":"bytes32"}],"name":"SetTokenSpecificPostfix","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"contractType","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"version","type":"uint256"},{"indexed":false,"internalType":"address","name":"author","type":"address"},{"indexed":false,"internalType":"string","name":"source","type":"string"},{"indexed":false,"internalType":"bytes","name":"signature","type":"bytes"}],"name":"UploadBytecode","type":"event"},{"inputs":[],"name":"AUDIT_REPORT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BYTECODE_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"auditor","type":"address"},{"internalType":"string","name":"name","type":"string"}],"name":"addAuditor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"domain","type":"bytes32"}],"name":"addPublicDomain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"}],"name":"allowPublicContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"}],"name":"allowSystemContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"cType","type":"bytes32"},{"internalType":"uint256","name":"ver","type":"uint256"},{"internalType":"bytes","name":"constructorParams","type":"bytes"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"deployer","type":"address"}],"name":"computeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"},{"components":[{"internalType":"address","name":"auditor","type":"address"},{"internalType":"string","name":"reportUrl","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct AuditReport","name":"report","type":"tuple"}],"name":"computeAuditReportHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"contractType","type":"bytes32"},{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"address","name":"author","type":"address"},{"internalType":"string","name":"source","type":"string"},{"internalType":"bytes","name":"authorSignature","type":"bytes"}],"internalType":"struct Bytecode","name":"bytecode","type":"tuple"}],"name":"computeBytecodeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"contractType","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"cType","type":"bytes32"},{"internalType":"uint256","name":"ver","type":"uint256"},{"internalType":"bytes","name":"constructorParams","type":"bytes"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"deploy","outputs":[{"internalType":"address","name":"newContract","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domainSeparatorV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"initCodeHash","type":"bytes32"}],"name":"forbidInitCode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"cType","type":"bytes32"},{"internalType":"uint256","name":"ver","type":"uint256"}],"name":"getAllowedBytecodeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getAuditReport","outputs":[{"components":[{"internalType":"address","name":"auditor","type":"address"},{"internalType":"string","name":"reportUrl","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct AuditReport","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"}],"name":"getAuditReports","outputs":[{"components":[{"internalType":"address","name":"auditor","type":"address"},{"internalType":"string","name":"reportUrl","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct AuditReport[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"auditor","type":"address"}],"name":"getAuditorName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAuditors","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"}],"name":"getBytecode","outputs":[{"components":[{"internalType":"bytes32","name":"contractType","type":"bytes32"},{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"address","name":"author","type":"address"},{"internalType":"string","name":"source","type":"string"},{"internalType":"bytes","name":"authorSignature","type":"bytes"}],"internalType":"struct Bytecode","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"cType","type":"bytes32"}],"name":"getContractTypeOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"deployedContract","type":"address"}],"name":"getDeployedContractBytecodeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"cType","type":"bytes32"},{"internalType":"uint256","name":"majorVersion","type":"uint256"}],"name":"getLatestMinorVersion","outputs":[{"internalType":"uint256","name":"ver","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"cType","type":"bytes32"},{"internalType":"uint256","name":"minorVersion","type":"uint256"}],"name":"getLatestPatchVersion","outputs":[{"internalType":"uint256","name":"ver","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"cType","type":"bytes32"}],"name":"getLatestVersion","outputs":[{"internalType":"uint256","name":"ver","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"}],"name":"getNumAuditReports","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPublicDomains","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSystemDomains","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTokenSpecificPostfix","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"cType","type":"bytes32"}],"name":"getVersions","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"auditor","type":"address"}],"name":"isAuditor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"}],"name":"isBytecodeAudited","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"}],"name":"isBytecodeUploaded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"deployedContract","type":"address"}],"name":"isDeployedFromRepository","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"initCodeHash","type":"bytes32"}],"name":"isInitCodeForbidden","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"domain","type":"bytes32"}],"name":"isPublicDomain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"domain","type":"bytes32"}],"name":"isSystemDomain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"auditor","type":"address"}],"name":"removeAuditor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"cType","type":"bytes32"}],"name":"removePublicContractType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes32","name":"postfix","type":"bytes32"}],"name":"setTokenSpecificPostfix","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"bytecodeHash","type":"bytes32"},{"components":[{"internalType":"address","name":"auditor","type":"address"},{"internalType":"string","name":"reportUrl","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct AuditReport","name":"auditReport","type":"tuple"}],"name":"submitAuditReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"contractType","type":"bytes32"},{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"address","name":"author","type":"address"},{"internalType":"string","name":"source","type":"string"},{"internalType":"bytes","name":"authorSignature","type":"bytes"}],"internalType":"struct Bytecode","name":"bytecode","type":"tuple"}],"name":"uploadBytecode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
61016060405234801562000011575f80fd5b506040516200480e3803806200480e83398101604081905262000034916200022a565b6200005f7f42595445434f44455f5245504f5349544f52590000000000000000000000000062000130565b6200006c61013662000164565b6001600160a01b03831660805262000085825f620001a7565b6101205262000096816001620001a7565b61014052815160208084019190912060e052815190820120610100526200012060e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020820152908101929092526060820152600160808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b60a05250503060c0525062000435565b6040515f5b82811a15620001475760010162000135565b808252602082018381525f82820152505060408101604052919050565b60606080604051019050602081016040525f8152805f19835b928101926030600a8206018453600a9004806200017d575050819003601f19909101908152919050565b5f602083511015620001c657620001be83620001df565b9050620001d9565b81620001d38482620002f7565b5060ff90505b92915050565b5f80829050601f8151111562000215578260405163305a27a960e01b81526004016200020c9190620003c3565b60405180910390fd5b8051620002228262000411565b179392505050565b5f602082840312156200023b575f80fd5b81516001600160a01b038116811462000252575f80fd5b9392505050565b634e487b7160e01b5f52604160045260245ffd5b600181811c908216806200028257607f821691505b602082108103620002a157634e487b7160e01b5f52602260045260245ffd5b50919050565b601f821115620002f257805f5260205f20601f840160051c81016020851015620002ce5750805b601f840160051c820191505b81811015620002ef575f8155600101620002da565b50505b505050565b81516001600160401b0381111562000313576200031362000259565b6200032b816200032484546200026d565b84620002a7565b602080601f83116001811462000361575f8415620003495750858301515b5f19600386901b1c1916600185901b178555620003bb565b5f85815260208120601f198616915b82811015620003915788860151825594840194600190910190840162000370565b5085821015620003af57878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b5f602080835283518060208501525f5b81811015620003f157858101830151858201604001528201620003d3565b505f604082860101526040601f19601f8301168501019250505092915050565b80516020808301519190811015620002a1575f1960209190910360031b1b16919050565b60805160a05160c05160e051610100516101205161014051614356620004b85f395f6117ed01525f6117c301525f6129a901525f61298101525f61290701525f61293001525f818161060d01528181610acf01528181610d8201528181611086015281816112de015281816116ea01528181612091015261214201526143565ff3fe608060405234801561000f575f80fd5b50600436106102e3575f3560e01c80637324c3af11610187578063c74f81e8116100dd578063dd3b014c11610093578063f709f3c01161006e578063f709f3c014610749578063fc0dd46e1461075c578063fffa7fdf1461076f575f80fd5b8063dd3b014c146106fb578063e6116cfd1461070e578063f438761114610721575f80fd5b8063cb2ef6f7116100c3578063cb2ef6f7146106a8578063cdad476d146106cf578063cff2c702146106f3575f80fd5b8063c74f81e814610682578063c955474414610695575f80fd5b80638bc2dc2d1161013d5780639738418c116101185780639738418c1461062f5780639aace0321461064f578063a98ac83a1461066f575f80fd5b80638bc2dc2d146105b95780638c660565146105e05780638da5cb5b14610608575f80fd5b806378e890ba1161016d57806378e890ba1461056c5780637f9b79a11461057457806384b0196e1461059e575f80fd5b80637324c3af14610546578063763b85bb14610559575f80fd5b80634251e6961161023c5780634ceff70e116101f257806357de4a6e116101cd57806357de4a6e146104df5780635ce8938f146104f45780636297f6da1461051f575f80fd5b80634ceff70e1461049957806354fd4d50146104ac57806355b8fcfd146104b5575f80fd5b806345ac41851161022257806345ac4185146104605780634637c2e21461047357806349b9055714610486575f80fd5b80634251e6961461040657806343b2389914610438575f80fd5b8063185b62391161029c57806334fc2e9e1161027757806334fc2e9e146103b35780633b85450e146103d35780633bb1bbf0146103f3575f80fd5b8063185b62391461036c5780631cbb53e71461038b57806329feed60146103a0575f80fd5b80630958394a116102cc5780630958394a146103315780630bc4976114610346578063170ecb1714610359575f80fd5b80630337f318146102e75780630682f2bf14610310575b5f80fd5b6102fa6102f5366004613797565b610782565b60405161030791906137fb565b60405180910390f35b61032361031e366004613882565b6109f1565b604051908152602001610307565b61034461033f366004613797565b610ac4565b005b6103236103543660046138b9565b610c6d565b610323610367366004613903565b610d0e565b61032361037a366004613797565b5f9081526004602052604090205490565b610393610d66565b6040516103079190613923565b6103446103ae36600461397a565b610d77565b6103c66103c13660046139a4565b610e30565b60405161030791906139bf565b6103e66103e1366004613903565b610ed9565b6040516103079190613a11565b610344610401366004613797565b61107b565b610428610414366004613797565b5f908152600d602052604090205460ff1690565b6040519015158152602001610307565b6103236104463660046139a4565b6001600160a01b03165f9081526002602052604090205490565b61042861046e366004613797565b61111d565b610344610481366004613797565b6112d3565b6104286104943660046139a4565b611330565b6103236104a7366004613903565b61133c565b61032361013681565b6104286104c33660046139a4565b6001600160a01b03165f90815260026020526040902054151590565b6104e7611361565b6040516103079190613a23565b610507610502366004613b08565b61136d565b6040516001600160a01b039091168152602001610307565b6103237fc4795df7bcdb7e9992b53843f03c7b94ea68994314dc33fade98e00424f41c2381565b610428610554366004613797565b6116d3565b610344610567366004613b5c565b6116df565b6103236117ad565b610323610582366004613903565b5f91825260056020908152604080842092845291905290205490565b6105a66117b6565b6040516103079796959493929190613bf6565b6103237f7abe26c408d04264c1fb41f696599cd461d516105b9fc798599f526439ba820781565b6105076105ee366004613797565b5f908152600f60205260409020546001600160a01b031690565b6105077f000000000000000000000000000000000000000000000000000000000000000081565b61064261063d366004613797565b611859565b6040516103079190613c7f565b61066261065d366004613797565b611875565b6040516103079190613c91565b61042861067d366004613797565b611a19565b6103446106903660046138b9565b611a25565b6103446106a3366004613882565b611cce565b6103237f42595445434f44455f5245504f5349544f52590000000000000000000000000081565b6104286106dd366004613797565b5f90815260036020526040902060020154151590565b610393612040565b610323610709366004613797565b61204c565b61034461071c3660046139a4565b612086565b61032361072f3660046139a4565b6001600160a01b03165f908152600e602052604090205490565b610344610757366004613797565b612137565b61050761076a366004613cf3565b61220b565b61034461077d366004613797565b612314565b6040805160c080820183525f808352602080840182905260608486018190528085018390526080850181905260a0850152858252600381528482208551938401865280548452600181015484830152600281018054875181850281018501895281815296979496929486019383018282801561082557602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610807575b505050918352505060038201546001600160a01b0316602082015260048201805460409092019161085590613d5d565b80601f016020809104026020016040519081016040528092919081815260200182805461088190613d5d565b80156108cc5780601f106108a3576101008083540402835291602001916108cc565b820191905f5260205f20905b8154815290600101906020018083116108af57829003601f168201915b505050505081526020016005820180546108e590613d5d565b80601f016020809104026020016040519081016040528092919081815260200182805461091190613d5d565b801561095c5780601f106109335761010080835404028352916020019161095c565b820191905f5260205f20905b81548152906001019060200180831161093f57829003601f168201915b50505050508152505090508060400151515f0361099457604051634d67fee360e11b8152600481018490526024015b60405180910390fd5b6040518060c00160405280825f01518152602001826020015181526020016109bf83604001516124ac565b815260200182606001516001600160a01b03168152602001826080015181526020018260a00151815250915050919050565b5f7f7abe26c408d04264c1fb41f696599cd461d516105b9fc798599f526439ba820782356020840135610a276040860186613d8f565b604051610a35929190613dd2565b604051908190039020610a4e60808701606088016139a4565b610a5b6080880188613d8f565b604051610a69929190613dd2565b604080519182900382206020830197909752810194909452606084019290925260808301526001600160a01b031660a082015260c081019190915260e001604051602081830303815290604052805190602001209050919050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610b0f57604051630cc479f960e01b815233600482015260240161098b565b610b1b6105548261250d565b15610c6a575f818152600f6020526040902080546001600160a01b031615610b765780546001600160a01b031916815560405182907faf79caa1a3bbb56f8c79ed5cef07aca618f7baf1cc7cb287e7958762f543891c905f90a25b5f60018201819055610b8a60048301612576565b80519091505f5b81811015610c65575f838281518110610bac57610bac613de1565b60200260200101519050610bcc818660040161258990919063ffffffff16565b505f856002015f610bdc84612594565b81526020019081526020015f20819055505f856003015f610bfc846125aa565b815260208082019290925260409081015f9081209390935588835260058252808320848452909152808220805490839055905190918391899184917f3a6ace7c9d30d9754dcd62229ab219cdd3e19cb89f79f6a43f0462448874e7c59190a45050600101610b91565b505050505b50565b5f7fc4795df7bcdb7e9992b53843f03c7b94ea68994314dc33fade98e00424f41c2383610c9d60208501856139a4565b610caa6020860186613d8f565b604051610cb8929190613dd2565b604051908190038120610cef9493929160200193845260208401929092526001600160a01b03166040830152606082015260800190565b6040516020818303038152906040528051906020012090505b92915050565b5f610d1983836125b6565b5f838152600f6020526040812060020190610d3384612594565b81526020019081526020015f20549050805f03610d0857604051634d422f8760e01b81526004810184905260240161098b565b6060610d726006612576565b905090565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610dc257604051630cc479f960e01b815233600482015260240161098b565b610dcb81612607565b6001600160a01b0382165f908152600e60205260409020548114610e2c576001600160a01b0382165f818152600e6020526040808220849055518392917fd268eef115aec03b6715b407096fe097c43703397ce2f32b5f3aea94e9377c5191a35b5050565b6001600160a01b0381165f908152600c60205260409020805460609190610e5690613d5d565b80601f0160208091040260200160405190810160405280929190818152602001828054610e8290613d5d565b8015610ecd5780601f10610ea457610100808354040283529160200191610ecd565b820191905f5260205f20905b815481529060010190602001808311610eb057829003601f168201915b50505050509050919050565b610f0560405180606001604052805f6001600160a01b0316815260200160608152602001606081525090565b5f838152600460205260409020805483908110610f2457610f24613de1565b5f918252602091829020604080516060810190915260039092020180546001600160a01b031682526001810180549293919291840191610f6390613d5d565b80601f0160208091040260200160405190810160405280929190818152602001828054610f8f90613d5d565b8015610fda5780601f10610fb157610100808354040283529160200191610fda565b820191905f5260205f20905b815481529060010190602001808311610fbd57829003601f168201915b50505050508152602001600282018054610ff390613d5d565b80601f016020809104026020016040519081016040528092919081815260200182805461101f90613d5d565b801561106a5780601f106110415761010080835404028352916020019161106a565b820191905f5260205f20905b81548152906001019060200180831161104d57829003601f168201915b505050505081525050905092915050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146110c657604051630cc479f960e01b815233600482015260240161098b565b5f818152600d602052604090205460ff16610c6a575f818152600d6020526040808220805460ff191660011790555182917f68b7a94d411933fb7a5e82cd942c291da2b2c8599fc89739e5aa07f6b7a4b6bf91a250565b5f81815260046020526040812054815b818110156112ca575f84815260046020526040812080548390811061115457611154613de1565b5f918252602091829020604080516060810190915260039092020180546001600160a01b03168252600181018054929391929184019161119390613d5d565b80601f01602080910402602001604051908101604052809291908181526020018280546111bf90613d5d565b801561120a5780601f106111e15761010080835404028352916020019161120a565b820191905f5260205f20905b8154815290600101906020018083116111ed57829003601f168201915b5050505050815260200160028201805461122390613d5d565b80601f016020809104026020016040519081016040528092919081815260200182805461124f90613d5d565b801561129a5780601f106112715761010080835404028352916020019161129a565b820191905f5260205f20905b81548152906001019060200180831161127d57829003601f168201915b50505050508152505090506112b1815f0151611330565b156112c157506001949350505050565b5060010161112d565b505f9392505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461131e57604051630cc479f960e01b815233600482015260240161098b565b61132781612649565b610c6a8161268b565b5f610d08600a8361270b565b5f61134783836125b6565b5f838152600f6020526040812060030190610d33846125aa565b6060610d72600a612576565b5f8481526005602090815260408083208684529091528120548082036113c9576040517f59eb7bbf000000000000000000000000000000000000000000000000000000008152600481018790526024810186905260440161098b565b5f81815260036020908152604080832060028101805483518186028101860190945280845291949361143893929083018282801561142e57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311611410575b50505050506124ac565b90506114438161272c565b6040805160208082018890523382840152825180830384018152606083019093528251920191909120905f9061147f9084908a90608001613df5565b60405160208183030381529060405290506114a1828280519060200120612783565b95506001600160a01b0386163b156114f0576040517f5a1ca1ef0000000000000000000000000000000000000000000000000000000081526001600160a01b038716600482015260240161098b565b6114fb5f838361278f565b5089866001600160a01b031663cb2ef6f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611539573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061155d9190613e23565b1415806115c9575088866001600160a01b03166354fd4d506040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115a2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c69190613e23565b14155b15611603576040517fa455096a0000000000000000000000000000000000000000000000000000000081526004810186905260240161098b565b6001600160a01b0386165f90815260026020526040908190208690555189908b9087907f985d7c3c40d322d1c4efd07d4ec7393e9d9afd6255b9262a71856ab733445b0b90611655908b908e90613e3a565b60405180910390a46040517ff2fde38b0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0387169063f2fde38b906024015f604051808303815f87803b1580156116b4575f80fd5b505af19250505080156116c5575060015b505050505050949350505050565b5f610d08600883612891565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461172a57604051630cc479f960e01b815233600482015260240161098b565b81611734816128a8565b61173f600a846128e8565b156117a8576001600160a01b0383165f908152600c602052604090206117658382613e9f565b50826001600160a01b03167f7bc1b27082213f1bc7985add466854d76b6ef6a785a766b5e1b7c135e3ccd8ff8360405161179f91906139bf565b60405180910390a25b505050565b5f610d726128fc565b5f606080828080836117e87f0000000000000000000000000000000000000000000000000000000000000000836129fa565b6118137f000000000000000000000000000000000000000000000000000000000000000060016129fa565b604080515f808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a5091985060019750309650945092509050565b5f818152600f60205260409020606090610d0890600401612576565b606060045f8381526020019081526020015f20805480602002602001604051908101604052809291908181526020015f905b82821015611a0e575f84815260209081902060408051606081019091526003850290910180546001600160a01b0316825260018101805492939192918401916118ef90613d5d565b80601f016020809104026020016040519081016040528092919081815260200182805461191b90613d5d565b80156119665780601f1061193d57610100808354040283529160200191611966565b820191905f5260205f20905b81548152906001019060200180831161194957829003601f168201915b5050505050815260200160028201805461197f90613d5d565b80601f01602080910402602001604051908101604052809291908181526020018280546119ab90613d5d565b80156119f65780601f106119cd576101008083540402835291602001916119f6565b820191905f5260205f20905b8154815290600101906020018083116119d957829003601f168201915b505050505081525050815260200190600101906118a7565b505050509050919050565b5f610d08600683612891565b5f82815260036020526040902060020154611a5657604051634d67fee360e11b81526004810183905260240161098b565b611a6e611a6660208301836139a4565b600a9061270b565b611abd57611a7f60208201826139a4565b6040517ff7607e280000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015260240161098b565b5f611ac88383610c6d565b90505f611b1d611ad783612aa3565b611ae46040860186613d8f565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612aea92505050565b9050611b2c60208401846139a4565b6001600160a01b0316816001600160a01b031614611b81576040517f757b72ce0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260240161098b565b5f848152600460205260408120805490915b81811015611c4557611ba86040870187613d8f565b604051611bb6929190613dd2565b6040518091039020838281548110611bd057611bd0613de1565b905f5260205f209060030201600201604051611bec9190613f5b565b604051809103902003611c3d576040517fefc766eb000000000000000000000000000000000000000000000000000000008152600481018890526001600160a01b038516602482015260440161098b565b600101611b93565b5081546001810183555f83815260209020869160030201611c668282614087565b50506001600160a01b038316867fbd11f75518ba12bcc581112f386a3994441a5be5c4db21520506db1424b20b17611ca16020890189613d8f565b611cae60408b018b613d8f565b604051611cbe94939291906141c1565b60405180910390a3505050505050565b611cde60808201606083016139a4565b611ce7816128a8565b5f611cf1836109f1565b5f8181526003602052604090206002015490915015611d0f57505050565b611d198335612b0c565b611d28833560208501356125b6565b82355f90815260056020908152604080832082870135845290915290205415611d7157604051630ed1518b60e11b8152833560048201526020840135602482015260440161098b565b466001148015611da25750611d8c60808401606085016139a4565b6001600160a01b0316336001600160a01b031614155b15611ddb576040517f3cef65f900000000000000000000000000000000000000000000000000000000815233600482015260240161098b565b5f611df5611de883612aa3565b611ae460a0870187613d8f565b9050611e0760808501606086016139a4565b6001600160a01b0316816001600160a01b031614611e5c576040517fe2ae390e0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260240161098b565b5f611e72611e6d6040870187613d8f565b612b4e565b90506040518060c00160405280865f0135815260200186602001358152602001828152602001866060016020810190611eab91906139a4565b6001600160a01b03168152602001611ec66080880188613d8f565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250505090825250602001611f0c60a0880188613d8f565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052509390945250508581526003602090815260409182902084518155848201516001820155918401518051929350611f7a92600285019291909101906136ed565b5060608201516003820180546001600160a01b0319166001600160a01b0390921691909117905560808201516004820190611fb59082613e9f565b5060a08201516005820190611fca9082613e9f565b50505060208501358535847f26ca1ecfd8f9fefc8490f8c95c54250c0a6d276f5997dee6e1c2b32d9e1d4fb361200660808a0160608b016139a4565b61201360808b018b613d8f565b61202060a08d018d613d8f565b6040516120319594939291906141f2565b60405180910390a45050505050565b6060610d726008612576565b5f818152600f60205260408120600101549081900361208157604051634d422f8760e01b81526004810183905260240161098b565b919050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146120d157604051630cc479f960e01b815233600482015260240161098b565b6120dc600a82612caa565b15610c6a576001600160a01b0381165f908152600c6020526040812061210191613750565b6040516001600160a01b038216907fc18d71bc530d1b91aa53821954282f1215c61f36942834456f9ac9eadd066543905f90a250565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461218257604051630cc479f960e01b815233600482015260240161098b565b5f818152600360205260409020600201546121b357604051634d67fee360e11b81526004810182905260240161098b565b6121bc8161111d565b6121dc57604051631dcddcc360e31b81526004810182905260240161098b565b5f81815260036020526040902080546121fc6121f78261250d565b612cbe565b6117a883828460010154612d3e565b5f8581526005602090815260408083208784528252808320548084526003835281842060028101805484518187028101870190955280855292949193869361228f9391929183018282801561142e57602002820191905f5260205f209081546001600160a01b031681526001909101906020018083116114105750505050506124ac565b90505f86866040516020016122b79291909182526001600160a01b0316602082015260400190565b6040516020818303038152906040528051906020012090505f82896040516020016122e3929190613df5565b6040516020818303038152906040529050612305828280519060200120612783565b9b9a5050505050505050505050565b5f8181526003602052604090206002015461234557604051634d67fee360e11b81526004810182905260240161098b565b61234e8161111d565b61236e57604051631dcddcc360e31b81526004810182905260240161098b565b5f81815260036020526040902080546123896105548261250d565b6123c2576040517fe6fe35dc0000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b60038201545f828152600f60205260409020546001600160a01b03918216911680612440575f838152600f602052604080822080546001600160a01b0319166001600160a01b0386169081179091559051909185917f8a7c28a279dc79bef2acfd98c3f20d8ef747b4bd030ca89013d969a7fcad3bf49190a361249d565b816001600160a01b0316816001600160a01b03161461249d576040517f82cc17b5000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b038316602482015260440161098b565b610c6585848660010154612d3e565b60605f5b825181101561250757816124dc8483815181106124cf576124cf613de1565b6020026020010151612df4565b6040516020016124ed929190613df5565b60408051601f1981840301815291905291506001016124b0565b50919050565b5f8061251883612e3c565b90505f612548604051806040016040528060028152602001611d1d60f11b81525083612e6e90919063ffffffff16565b90505f1981036125635761255b82612e7a565b949350505050565b61255b612571835f84612ea2565b612e7a565b60605f61258283612f07565b9392505050565b5f6125828383612f5f565b5f6125a0606483614247565b610d08908361426e565b5f6125a0600a83614247565b60648110806125c657506103e781115b15610e2c576040517fdce2db60000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260440161098b565b61261081613042565b610c6a576040517f59a757220000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b61265281613054565b610c6a576040517fd605933b0000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b61269481611a19565b156126ce576040517f08b7bec90000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b6126d960088261306b565b15610c6a5760405181907fbf48b0fded1fb4fad195adb1c16074c500ce5da8ab9f94fe494eba193a1b6edd905f90a250565b6001600160a01b0381165f9081526001830160205260408120541515612582565b80516020808301919091205f818152600d90925260409091205460ff1615610e2c576040517f4d1f13f00000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b5f612582838330613076565b5f834710156127e05760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e6365000000604482015260640161098b565b81515f036128305760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f604482015260640161098b565b8282516020840186f590506001600160a01b0381166125825760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f7900000000000000604482015260640161098b565b5f8181526001830160205260408120541515612582565b6001600160a01b038116610c6a576040517fb2335f2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612582836001600160a01b03841661309f565b5f6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361295257507f000000000000000000000000000000000000000000000000000000000000000090565b610d72604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f00000000000000000000000000000000000000000000000000000000000000006060820152600160808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b606060ff8314612a1457612a0d836130eb565b9050610d08565b818054612a2090613d5d565b80601f0160208091040260200160405190810160405280929190818152602001828054612a4c90613d5d565b8015612a975780601f10612a6e57610100808354040283529160200191612a97565b820191905f5260205f20905b815481529060010190602001808311612a7a57829003601f168201915b50505050509050610d08565b5f610d08612aaf6128fc565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b5f805f612af78585613128565b91509150612b048161316a565b509392505050565b612b15816132ce565b610c6a576040517fd93f96330000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b6060615fb45f839003612b8d576040517f3a67a86400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81612b9a60018661426e565b612ba49190614281565b612baf906001614294565b90508067ffffffffffffffff811115612bca57612bca613a63565b604051908082528060200260200182016040528015612bf3578160200160208202803683370190505b5092505f5b81811015612ca1575f612c0b84836142a7565b90505f612c188583614294565b905086811115612c255750855b612c6d612c3482848a8c6142be565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061332692505050565b868481518110612c7f57612c7f613de1565b6001600160a01b03909216602092830291909101909101525050600101612bf8565b50505092915050565b5f612582836001600160a01b038416612f5f565b612cc7816116d3565b15612d01576040517fd0bdb3ae0000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b612d0c60068261306b565b15610c6a5760405181907f20352ef9ad91057d3267998ab4fb71a6f13a6c130dd2ad17d7a79c859af6d70c905f90a250565b5f828152600560209081526040808320848452909152902054839003612d6357505050565b5f82815260056020908152604080832084845290915290205415612da457604051630ed1518b60e11b8152600481018390526024810182905260440161098b565b5f828152600560209081526040808320848452909152808220859055518291849186917f38ba0ee63038c97028a7faa932f9f0231f37310fe7ded293204b9c7da39d69c791a46117a8828261336c565b6060813b80612e0a576311052bb45f526004601cfd5b600181039050604051915061ffe0603f82011682016040528082525f8160208401015280600160208401853c50919050565b6040515f5b82811a15612e5157600101612e41565b808252602082018381525f82820152505060408101604052919050565b5f61258283835f613410565b805160218110612e915763ec92f9a35f526004601cfd5b9081015160209190910360031b1b90565b60608351828111612eb1578092505b838111612ebc578093505b5081831015612582575060405182820380825293830193601f19601f820181165b8681015184820152810180612edd57505f83830160200152603f9091011681016040529392505050565b6060815f01805480602002602001604051908101604052809291908181526020018280548015610ecd57602002820191905f5260205f20905b815481526020019060010190808311612f405750505050509050919050565b5f8181526001830160205260408120548015613039575f612f8160018361426e565b85549091505f90612f949060019061426e565b9050818114612ff3575f865f018281548110612fb257612fb2613de1565b905f5260205f200154905080875f018481548110612fd257612fd2613de1565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080613004576130046142e5565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610d08565b5f915050610d08565b5f610d0861304f83612e3c565b6134df565b5f8115801590610d085750610d0861304f83612e3c565b5f612582838361309f565b5f604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b5f8181526001830160205260408120546130e457508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610d08565b505f610d08565b60605f6130f7836134fa565b6040805160208082528183019092529192505f91906020820181803683375050509182525060208101929092525090565b5f80825160410361315c576020830151604084015160608501515f1a6131508782858561353a565b94509450505050613163565b505f905060025b9250929050565b5f81600481111561317d5761317d6142f9565b036131855750565b6001816004811115613199576131996142f9565b036131e65760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161098b565b60028160048111156131fa576131fa6142f9565b036132475760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161098b565b600381600481111561325b5761325b6142f9565b03610c6a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f7565000000000000000000000000000000000000000000000000000000000000606482015260840161098b565b5f806132d98361250d565b90506132e481613054565b6132f057505f92915050565b5f6132fa846135f7565b905061330581613042565b61331257505f9392505050565b61331c828261365d565b9093149392505050565b5f8151600181018060401b6bfd61000080600a3d393df3001761ffff8211850152600a8101601585015ff0925050816133665763301164255f526004601cfd5b90915290565b5f828152600f60205260409020600181015482111561338d57600181018290555b5f61339783612594565b5f8181526002840160205260409020549091508311156133c4575f81815260028301602052604090208390555b5f6133ce846125aa565b5f8181526003850160205260409020549091508411156133fb575f81815260038401602052604090208490555b613408600484018561306b565b505050505050565b5f835183516134305780831161342857829150612b04565b809150612b04565b8351602086015f19935084810196506001828483010301601f831660200360031b6020880151858810838b101661346b575050505050612b04565b602085106134b0578460208a01205b818b5118831c6134975780868c200361349757848b0397506134a5565b60018b019a50838b1061347a575b505050505050612b04565b808a5118821c6134c457838a0396506134d2565b60018a019950828a106134b0575b5050505050509392505050565b5f610d08826f07fffffe87fffffe03ff0000000000006136a6565b5f60ff8216601f811115610d08576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561356f57505f905060036135ee565b604080515f8082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156135c0573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b0381166135e8575f600192509250506135ee565b91505f90505b94509492505050565b5f8061360283612e3c565b90505f613632604051806040016040528060028152602001611d1d60f11b81525083612e6e90919063ffffffff16565b90505f19810361364557505f9392505050565b61255b612571613656836002614294565b84906136df565b5f81810361366c575081610d08565b61258261367884612e3c565b61368184612e3c565b60405160200161369292919061430d565b604051602081830303815290604052612e7a565b815160019015610d08578160801b60801c60208401845181015b8282515f1a1c84169350600182019150808210841615612ca1576136c0565b606061258283835f19612ea2565b828054828255905f5260205f20908101928215613740579160200282015b8281111561374057825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061370b565b5061374c929150613783565b5090565b50805461375c90613d5d565b5f825580601f1061376b575050565b601f0160209004905f5260205f2090810190610c6a91905b5b8082111561374c575f8155600101613784565b5f602082840312156137a7575f80fd5b5035919050565b5f5b838110156137c85781810151838201526020016137b0565b50505f910152565b5f81518084526137e78160208601602086016137ae565b601f01601f19169290920160200192915050565b6020815281516020820152602082015160408201525f604083015160c0606084015261382a60e08401826137d0565b90506001600160a01b0360608501511660808401526080840151601f19808584030160a086015261385b83836137d0565b925060a08601519150808584030160c08601525061387982826137d0565b95945050505050565b5f60208284031215613892575f80fd5b813567ffffffffffffffff8111156138a8575f80fd5b820160c08185031215612582575f80fd5b5f80604083850312156138ca575f80fd5b82359150602083013567ffffffffffffffff8111156138e7575f80fd5b8301606081860312156138f8575f80fd5b809150509250929050565b5f8060408385031215613914575f80fd5b50508035926020909101359150565b602080825282518282018190525f9190848201906040850190845b8181101561395a5783518352928401929184019160010161393e565b50909695505050505050565b6001600160a01b0381168114610c6a575f80fd5b5f806040838503121561398b575f80fd5b823561399681613966565b946020939093013593505050565b5f602082840312156139b4575f80fd5b813561258281613966565b602081525f61258260208301846137d0565b6001600160a01b0381511682525f6020820151606060208501526139f860608501826137d0565b90506040830151848203604086015261387982826137d0565b602081525f61258260208301846139d1565b602080825282518282018190525f9190848201906040850190845b8181101561395a5783516001600160a01b031683529284019291840191600101613a3e565b634e487b7160e01b5f52604160045260245ffd5b5f67ffffffffffffffff80841115613a9157613a91613a63565b604051601f8501601f19908116603f01168101908282118183101715613ab957613ab9613a63565b81604052809350858152868686011115613ad1575f80fd5b858560208301375f602087830101525050509392505050565b5f82601f830112613af9575f80fd5b61258283833560208501613a77565b5f805f8060808587031215613b1b575f80fd5b8435935060208501359250604085013567ffffffffffffffff811115613b3f575f80fd5b613b4b87828801613aea565b949793965093946060013593505050565b5f8060408385031215613b6d575f80fd5b8235613b7881613966565b9150602083013567ffffffffffffffff811115613b93575f80fd5b8301601f81018513613ba3575f80fd5b613bb285823560208401613a77565b9150509250929050565b5f815180845260208085019450602084015f5b83811015613beb57815187529582019590820190600101613bcf565b509495945050505050565b7fff000000000000000000000000000000000000000000000000000000000000008816815260e060208201525f613c3060e08301896137d0565b8281036040840152613c4281896137d0565b90508660608401526001600160a01b03861660808401528460a084015282810360c0840152613c718185613bbc565b9a9950505050505050505050565b602081525f6125826020830184613bbc565b5f60208083016020845280855180835260408601915060408160051b8701019250602087015f5b82811015613ce657603f19888603018452613cd48583516139d1565b94509285019290850190600101613cb8565b5092979650505050505050565b5f805f805f60a08688031215613d07575f80fd5b8535945060208601359350604086013567ffffffffffffffff811115613d2b575f80fd5b613d3788828901613aea565b935050606086013591506080860135613d4f81613966565b809150509295509295909350565b600181811c90821680613d7157607f821691505b60208210810361250757634e487b7160e01b5f52602260045260245ffd5b5f808335601e19843603018112613da4575f80fd5b83018035915067ffffffffffffffff821115613dbe575f80fd5b602001915036819003821315613163575f80fd5b818382375f9101908152919050565b634e487b7160e01b5f52603260045260245ffd5b5f8351613e068184602088016137ae565b835190830190613e1a8183602088016137ae565b01949350505050565b5f60208284031215613e33575f80fd5b5051919050565b6001600160a01b0383168152604060208201525f61255b60408301846137d0565b601f8211156117a857805f5260205f20601f840160051c81016020851015613e805750805b601f840160051c820191505b81811015610c65575f8155600101613e8c565b815167ffffffffffffffff811115613eb957613eb9613a63565b613ecd81613ec78454613d5d565b84613e5b565b602080601f831160018114613f00575f8415613ee95750858301515b5f19600386901b1c1916600185901b178555613408565b5f85815260208120601f198616915b82811015613f2e57888601518255948401946001909101908401613f0f565b5085821015613f4b57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f808354613f6881613d5d565b60018281168015613f805760018114613f9557613fc1565b60ff1984168752821515830287019450613fc1565b875f526020805f205f5b85811015613fb85781548a820152908401908201613f9f565b50505082870194505b50929695505050505050565b67ffffffffffffffff831115613fe557613fe5613a63565b613ff983613ff38354613d5d565b83613e5b565b5f601f84116001811461402a575f85156140135750838201355b5f19600387901b1c1916600186901b178355610c65565b5f83815260208120601f198716915b828110156140595786850135825560209485019460019092019101614039565b5086821015614075575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b813561409281613966565b6001600160a01b0381166001600160a01b031983541617825550600180820160206140c06020860186613d8f565b67ffffffffffffffff8111156140d8576140d8613a63565b6140ec816140e68654613d5d565b86613e5b565b5f601f82116001811461411d575f83156141065750838201355b5f19600385901b1c1916600184901b178655614171565b5f86815260208120601f198516915b82811015614149578685013582559387019390890190870161412c565b5084821015614165575f1960f88660031b161c19848701351681555b505060018360011b0186555b505050505050506141856040830183613d8f565b614193818360028601613fcd565b50505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b604081525f6141d4604083018688614199565b82810360208401526141e7818587614199565b979650505050505050565b6001600160a01b0386168152606060208201525f614214606083018688614199565b8281036040840152614227818587614199565b98975050505050505050565b634e487b7160e01b5f52601260045260245ffd5b5f8261425557614255614233565b500690565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610d0857610d0861425a565b5f8261428f5761428f614233565b500490565b80820180821115610d0857610d0861425a565b8082028115828204841417610d0857610d0861425a565b5f80858511156142cc575f80fd5b838611156142d8575f80fd5b5050820193919092039150565b634e487b7160e01b5f52603160045260245ffd5b634e487b7160e01b5f52602160045260245ffd5b5f835161431e8184602088016137ae565b611d1d60f11b908301908152835161433d8160028401602088016137ae565b0160020194935050505056fea164736f6c6343000817000a00000000000000000000000018d162c462981662d76ebe1be8ab24ad317d04f8
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106102e3575f3560e01c80637324c3af11610187578063c74f81e8116100dd578063dd3b014c11610093578063f709f3c01161006e578063f709f3c014610749578063fc0dd46e1461075c578063fffa7fdf1461076f575f80fd5b8063dd3b014c146106fb578063e6116cfd1461070e578063f438761114610721575f80fd5b8063cb2ef6f7116100c3578063cb2ef6f7146106a8578063cdad476d146106cf578063cff2c702146106f3575f80fd5b8063c74f81e814610682578063c955474414610695575f80fd5b80638bc2dc2d1161013d5780639738418c116101185780639738418c1461062f5780639aace0321461064f578063a98ac83a1461066f575f80fd5b80638bc2dc2d146105b95780638c660565146105e05780638da5cb5b14610608575f80fd5b806378e890ba1161016d57806378e890ba1461056c5780637f9b79a11461057457806384b0196e1461059e575f80fd5b80637324c3af14610546578063763b85bb14610559575f80fd5b80634251e6961161023c5780634ceff70e116101f257806357de4a6e116101cd57806357de4a6e146104df5780635ce8938f146104f45780636297f6da1461051f575f80fd5b80634ceff70e1461049957806354fd4d50146104ac57806355b8fcfd146104b5575f80fd5b806345ac41851161022257806345ac4185146104605780634637c2e21461047357806349b9055714610486575f80fd5b80634251e6961461040657806343b2389914610438575f80fd5b8063185b62391161029c57806334fc2e9e1161027757806334fc2e9e146103b35780633b85450e146103d35780633bb1bbf0146103f3575f80fd5b8063185b62391461036c5780631cbb53e71461038b57806329feed60146103a0575f80fd5b80630958394a116102cc5780630958394a146103315780630bc4976114610346578063170ecb1714610359575f80fd5b80630337f318146102e75780630682f2bf14610310575b5f80fd5b6102fa6102f5366004613797565b610782565b60405161030791906137fb565b60405180910390f35b61032361031e366004613882565b6109f1565b604051908152602001610307565b61034461033f366004613797565b610ac4565b005b6103236103543660046138b9565b610c6d565b610323610367366004613903565b610d0e565b61032361037a366004613797565b5f9081526004602052604090205490565b610393610d66565b6040516103079190613923565b6103446103ae36600461397a565b610d77565b6103c66103c13660046139a4565b610e30565b60405161030791906139bf565b6103e66103e1366004613903565b610ed9565b6040516103079190613a11565b610344610401366004613797565b61107b565b610428610414366004613797565b5f908152600d602052604090205460ff1690565b6040519015158152602001610307565b6103236104463660046139a4565b6001600160a01b03165f9081526002602052604090205490565b61042861046e366004613797565b61111d565b610344610481366004613797565b6112d3565b6104286104943660046139a4565b611330565b6103236104a7366004613903565b61133c565b61032361013681565b6104286104c33660046139a4565b6001600160a01b03165f90815260026020526040902054151590565b6104e7611361565b6040516103079190613a23565b610507610502366004613b08565b61136d565b6040516001600160a01b039091168152602001610307565b6103237fc4795df7bcdb7e9992b53843f03c7b94ea68994314dc33fade98e00424f41c2381565b610428610554366004613797565b6116d3565b610344610567366004613b5c565b6116df565b6103236117ad565b610323610582366004613903565b5f91825260056020908152604080842092845291905290205490565b6105a66117b6565b6040516103079796959493929190613bf6565b6103237f7abe26c408d04264c1fb41f696599cd461d516105b9fc798599f526439ba820781565b6105076105ee366004613797565b5f908152600f60205260409020546001600160a01b031690565b6105077f00000000000000000000000018d162c462981662d76ebe1be8ab24ad317d04f881565b61064261063d366004613797565b611859565b6040516103079190613c7f565b61066261065d366004613797565b611875565b6040516103079190613c91565b61042861067d366004613797565b611a19565b6103446106903660046138b9565b611a25565b6103446106a3366004613882565b611cce565b6103237f42595445434f44455f5245504f5349544f52590000000000000000000000000081565b6104286106dd366004613797565b5f90815260036020526040902060020154151590565b610393612040565b610323610709366004613797565b61204c565b61034461071c3660046139a4565b612086565b61032361072f3660046139a4565b6001600160a01b03165f908152600e602052604090205490565b610344610757366004613797565b612137565b61050761076a366004613cf3565b61220b565b61034461077d366004613797565b612314565b6040805160c080820183525f808352602080840182905260608486018190528085018390526080850181905260a0850152858252600381528482208551938401865280548452600181015484830152600281018054875181850281018501895281815296979496929486019383018282801561082557602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610807575b505050918352505060038201546001600160a01b0316602082015260048201805460409092019161085590613d5d565b80601f016020809104026020016040519081016040528092919081815260200182805461088190613d5d565b80156108cc5780601f106108a3576101008083540402835291602001916108cc565b820191905f5260205f20905b8154815290600101906020018083116108af57829003601f168201915b505050505081526020016005820180546108e590613d5d565b80601f016020809104026020016040519081016040528092919081815260200182805461091190613d5d565b801561095c5780601f106109335761010080835404028352916020019161095c565b820191905f5260205f20905b81548152906001019060200180831161093f57829003601f168201915b50505050508152505090508060400151515f0361099457604051634d67fee360e11b8152600481018490526024015b60405180910390fd5b6040518060c00160405280825f01518152602001826020015181526020016109bf83604001516124ac565b815260200182606001516001600160a01b03168152602001826080015181526020018260a00151815250915050919050565b5f7f7abe26c408d04264c1fb41f696599cd461d516105b9fc798599f526439ba820782356020840135610a276040860186613d8f565b604051610a35929190613dd2565b604051908190039020610a4e60808701606088016139a4565b610a5b6080880188613d8f565b604051610a69929190613dd2565b604080519182900382206020830197909752810194909452606084019290925260808301526001600160a01b031660a082015260c081019190915260e001604051602081830303815290604052805190602001209050919050565b336001600160a01b037f00000000000000000000000018d162c462981662d76ebe1be8ab24ad317d04f81614610b0f57604051630cc479f960e01b815233600482015260240161098b565b610b1b6105548261250d565b15610c6a575f818152600f6020526040902080546001600160a01b031615610b765780546001600160a01b031916815560405182907faf79caa1a3bbb56f8c79ed5cef07aca618f7baf1cc7cb287e7958762f543891c905f90a25b5f60018201819055610b8a60048301612576565b80519091505f5b81811015610c65575f838281518110610bac57610bac613de1565b60200260200101519050610bcc818660040161258990919063ffffffff16565b505f856002015f610bdc84612594565b81526020019081526020015f20819055505f856003015f610bfc846125aa565b815260208082019290925260409081015f9081209390935588835260058252808320848452909152808220805490839055905190918391899184917f3a6ace7c9d30d9754dcd62229ab219cdd3e19cb89f79f6a43f0462448874e7c59190a45050600101610b91565b505050505b50565b5f7fc4795df7bcdb7e9992b53843f03c7b94ea68994314dc33fade98e00424f41c2383610c9d60208501856139a4565b610caa6020860186613d8f565b604051610cb8929190613dd2565b604051908190038120610cef9493929160200193845260208401929092526001600160a01b03166040830152606082015260800190565b6040516020818303038152906040528051906020012090505b92915050565b5f610d1983836125b6565b5f838152600f6020526040812060020190610d3384612594565b81526020019081526020015f20549050805f03610d0857604051634d422f8760e01b81526004810184905260240161098b565b6060610d726006612576565b905090565b336001600160a01b037f00000000000000000000000018d162c462981662d76ebe1be8ab24ad317d04f81614610dc257604051630cc479f960e01b815233600482015260240161098b565b610dcb81612607565b6001600160a01b0382165f908152600e60205260409020548114610e2c576001600160a01b0382165f818152600e6020526040808220849055518392917fd268eef115aec03b6715b407096fe097c43703397ce2f32b5f3aea94e9377c5191a35b5050565b6001600160a01b0381165f908152600c60205260409020805460609190610e5690613d5d565b80601f0160208091040260200160405190810160405280929190818152602001828054610e8290613d5d565b8015610ecd5780601f10610ea457610100808354040283529160200191610ecd565b820191905f5260205f20905b815481529060010190602001808311610eb057829003601f168201915b50505050509050919050565b610f0560405180606001604052805f6001600160a01b0316815260200160608152602001606081525090565b5f838152600460205260409020805483908110610f2457610f24613de1565b5f918252602091829020604080516060810190915260039092020180546001600160a01b031682526001810180549293919291840191610f6390613d5d565b80601f0160208091040260200160405190810160405280929190818152602001828054610f8f90613d5d565b8015610fda5780601f10610fb157610100808354040283529160200191610fda565b820191905f5260205f20905b815481529060010190602001808311610fbd57829003601f168201915b50505050508152602001600282018054610ff390613d5d565b80601f016020809104026020016040519081016040528092919081815260200182805461101f90613d5d565b801561106a5780601f106110415761010080835404028352916020019161106a565b820191905f5260205f20905b81548152906001019060200180831161104d57829003601f168201915b505050505081525050905092915050565b336001600160a01b037f00000000000000000000000018d162c462981662d76ebe1be8ab24ad317d04f816146110c657604051630cc479f960e01b815233600482015260240161098b565b5f818152600d602052604090205460ff16610c6a575f818152600d6020526040808220805460ff191660011790555182917f68b7a94d411933fb7a5e82cd942c291da2b2c8599fc89739e5aa07f6b7a4b6bf91a250565b5f81815260046020526040812054815b818110156112ca575f84815260046020526040812080548390811061115457611154613de1565b5f918252602091829020604080516060810190915260039092020180546001600160a01b03168252600181018054929391929184019161119390613d5d565b80601f01602080910402602001604051908101604052809291908181526020018280546111bf90613d5d565b801561120a5780601f106111e15761010080835404028352916020019161120a565b820191905f5260205f20905b8154815290600101906020018083116111ed57829003601f168201915b5050505050815260200160028201805461122390613d5d565b80601f016020809104026020016040519081016040528092919081815260200182805461124f90613d5d565b801561129a5780601f106112715761010080835404028352916020019161129a565b820191905f5260205f20905b81548152906001019060200180831161127d57829003601f168201915b50505050508152505090506112b1815f0151611330565b156112c157506001949350505050565b5060010161112d565b505f9392505050565b336001600160a01b037f00000000000000000000000018d162c462981662d76ebe1be8ab24ad317d04f8161461131e57604051630cc479f960e01b815233600482015260240161098b565b61132781612649565b610c6a8161268b565b5f610d08600a8361270b565b5f61134783836125b6565b5f838152600f6020526040812060030190610d33846125aa565b6060610d72600a612576565b5f8481526005602090815260408083208684529091528120548082036113c9576040517f59eb7bbf000000000000000000000000000000000000000000000000000000008152600481018790526024810186905260440161098b565b5f81815260036020908152604080832060028101805483518186028101860190945280845291949361143893929083018282801561142e57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311611410575b50505050506124ac565b90506114438161272c565b6040805160208082018890523382840152825180830384018152606083019093528251920191909120905f9061147f9084908a90608001613df5565b60405160208183030381529060405290506114a1828280519060200120612783565b95506001600160a01b0386163b156114f0576040517f5a1ca1ef0000000000000000000000000000000000000000000000000000000081526001600160a01b038716600482015260240161098b565b6114fb5f838361278f565b5089866001600160a01b031663cb2ef6f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611539573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061155d9190613e23565b1415806115c9575088866001600160a01b03166354fd4d506040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115a2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c69190613e23565b14155b15611603576040517fa455096a0000000000000000000000000000000000000000000000000000000081526004810186905260240161098b565b6001600160a01b0386165f90815260026020526040908190208690555189908b9087907f985d7c3c40d322d1c4efd07d4ec7393e9d9afd6255b9262a71856ab733445b0b90611655908b908e90613e3a565b60405180910390a46040517ff2fde38b0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0387169063f2fde38b906024015f604051808303815f87803b1580156116b4575f80fd5b505af19250505080156116c5575060015b505050505050949350505050565b5f610d08600883612891565b336001600160a01b037f00000000000000000000000018d162c462981662d76ebe1be8ab24ad317d04f8161461172a57604051630cc479f960e01b815233600482015260240161098b565b81611734816128a8565b61173f600a846128e8565b156117a8576001600160a01b0383165f908152600c602052604090206117658382613e9f565b50826001600160a01b03167f7bc1b27082213f1bc7985add466854d76b6ef6a785a766b5e1b7c135e3ccd8ff8360405161179f91906139bf565b60405180910390a25b505050565b5f610d726128fc565b5f606080828080836117e87f42595445434f44455f5245504f5349544f525900000000000000000000000013836129fa565b6118137f333130000000000000000000000000000000000000000000000000000000000360016129fa565b604080515f808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a5091985060019750309650945092509050565b5f818152600f60205260409020606090610d0890600401612576565b606060045f8381526020019081526020015f20805480602002602001604051908101604052809291908181526020015f905b82821015611a0e575f84815260209081902060408051606081019091526003850290910180546001600160a01b0316825260018101805492939192918401916118ef90613d5d565b80601f016020809104026020016040519081016040528092919081815260200182805461191b90613d5d565b80156119665780601f1061193d57610100808354040283529160200191611966565b820191905f5260205f20905b81548152906001019060200180831161194957829003601f168201915b5050505050815260200160028201805461197f90613d5d565b80601f01602080910402602001604051908101604052809291908181526020018280546119ab90613d5d565b80156119f65780601f106119cd576101008083540402835291602001916119f6565b820191905f5260205f20905b8154815290600101906020018083116119d957829003601f168201915b505050505081525050815260200190600101906118a7565b505050509050919050565b5f610d08600683612891565b5f82815260036020526040902060020154611a5657604051634d67fee360e11b81526004810183905260240161098b565b611a6e611a6660208301836139a4565b600a9061270b565b611abd57611a7f60208201826139a4565b6040517ff7607e280000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015260240161098b565b5f611ac88383610c6d565b90505f611b1d611ad783612aa3565b611ae46040860186613d8f565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612aea92505050565b9050611b2c60208401846139a4565b6001600160a01b0316816001600160a01b031614611b81576040517f757b72ce0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260240161098b565b5f848152600460205260408120805490915b81811015611c4557611ba86040870187613d8f565b604051611bb6929190613dd2565b6040518091039020838281548110611bd057611bd0613de1565b905f5260205f209060030201600201604051611bec9190613f5b565b604051809103902003611c3d576040517fefc766eb000000000000000000000000000000000000000000000000000000008152600481018890526001600160a01b038516602482015260440161098b565b600101611b93565b5081546001810183555f83815260209020869160030201611c668282614087565b50506001600160a01b038316867fbd11f75518ba12bcc581112f386a3994441a5be5c4db21520506db1424b20b17611ca16020890189613d8f565b611cae60408b018b613d8f565b604051611cbe94939291906141c1565b60405180910390a3505050505050565b611cde60808201606083016139a4565b611ce7816128a8565b5f611cf1836109f1565b5f8181526003602052604090206002015490915015611d0f57505050565b611d198335612b0c565b611d28833560208501356125b6565b82355f90815260056020908152604080832082870135845290915290205415611d7157604051630ed1518b60e11b8152833560048201526020840135602482015260440161098b565b466001148015611da25750611d8c60808401606085016139a4565b6001600160a01b0316336001600160a01b031614155b15611ddb576040517f3cef65f900000000000000000000000000000000000000000000000000000000815233600482015260240161098b565b5f611df5611de883612aa3565b611ae460a0870187613d8f565b9050611e0760808501606086016139a4565b6001600160a01b0316816001600160a01b031614611e5c576040517fe2ae390e0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260240161098b565b5f611e72611e6d6040870187613d8f565b612b4e565b90506040518060c00160405280865f0135815260200186602001358152602001828152602001866060016020810190611eab91906139a4565b6001600160a01b03168152602001611ec66080880188613d8f565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250505090825250602001611f0c60a0880188613d8f565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052509390945250508581526003602090815260409182902084518155848201516001820155918401518051929350611f7a92600285019291909101906136ed565b5060608201516003820180546001600160a01b0319166001600160a01b0390921691909117905560808201516004820190611fb59082613e9f565b5060a08201516005820190611fca9082613e9f565b50505060208501358535847f26ca1ecfd8f9fefc8490f8c95c54250c0a6d276f5997dee6e1c2b32d9e1d4fb361200660808a0160608b016139a4565b61201360808b018b613d8f565b61202060a08d018d613d8f565b6040516120319594939291906141f2565b60405180910390a45050505050565b6060610d726008612576565b5f818152600f60205260408120600101549081900361208157604051634d422f8760e01b81526004810183905260240161098b565b919050565b336001600160a01b037f00000000000000000000000018d162c462981662d76ebe1be8ab24ad317d04f816146120d157604051630cc479f960e01b815233600482015260240161098b565b6120dc600a82612caa565b15610c6a576001600160a01b0381165f908152600c6020526040812061210191613750565b6040516001600160a01b038216907fc18d71bc530d1b91aa53821954282f1215c61f36942834456f9ac9eadd066543905f90a250565b336001600160a01b037f00000000000000000000000018d162c462981662d76ebe1be8ab24ad317d04f8161461218257604051630cc479f960e01b815233600482015260240161098b565b5f818152600360205260409020600201546121b357604051634d67fee360e11b81526004810182905260240161098b565b6121bc8161111d565b6121dc57604051631dcddcc360e31b81526004810182905260240161098b565b5f81815260036020526040902080546121fc6121f78261250d565b612cbe565b6117a883828460010154612d3e565b5f8581526005602090815260408083208784528252808320548084526003835281842060028101805484518187028101870190955280855292949193869361228f9391929183018282801561142e57602002820191905f5260205f209081546001600160a01b031681526001909101906020018083116114105750505050506124ac565b90505f86866040516020016122b79291909182526001600160a01b0316602082015260400190565b6040516020818303038152906040528051906020012090505f82896040516020016122e3929190613df5565b6040516020818303038152906040529050612305828280519060200120612783565b9b9a5050505050505050505050565b5f8181526003602052604090206002015461234557604051634d67fee360e11b81526004810182905260240161098b565b61234e8161111d565b61236e57604051631dcddcc360e31b81526004810182905260240161098b565b5f81815260036020526040902080546123896105548261250d565b6123c2576040517fe6fe35dc0000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b60038201545f828152600f60205260409020546001600160a01b03918216911680612440575f838152600f602052604080822080546001600160a01b0319166001600160a01b0386169081179091559051909185917f8a7c28a279dc79bef2acfd98c3f20d8ef747b4bd030ca89013d969a7fcad3bf49190a361249d565b816001600160a01b0316816001600160a01b03161461249d576040517f82cc17b5000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b038316602482015260440161098b565b610c6585848660010154612d3e565b60605f5b825181101561250757816124dc8483815181106124cf576124cf613de1565b6020026020010151612df4565b6040516020016124ed929190613df5565b60408051601f1981840301815291905291506001016124b0565b50919050565b5f8061251883612e3c565b90505f612548604051806040016040528060028152602001611d1d60f11b81525083612e6e90919063ffffffff16565b90505f1981036125635761255b82612e7a565b949350505050565b61255b612571835f84612ea2565b612e7a565b60605f61258283612f07565b9392505050565b5f6125828383612f5f565b5f6125a0606483614247565b610d08908361426e565b5f6125a0600a83614247565b60648110806125c657506103e781115b15610e2c576040517fdce2db60000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260440161098b565b61261081613042565b610c6a576040517f59a757220000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b61265281613054565b610c6a576040517fd605933b0000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b61269481611a19565b156126ce576040517f08b7bec90000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b6126d960088261306b565b15610c6a5760405181907fbf48b0fded1fb4fad195adb1c16074c500ce5da8ab9f94fe494eba193a1b6edd905f90a250565b6001600160a01b0381165f9081526001830160205260408120541515612582565b80516020808301919091205f818152600d90925260409091205460ff1615610e2c576040517f4d1f13f00000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b5f612582838330613076565b5f834710156127e05760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e6365000000604482015260640161098b565b81515f036128305760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f604482015260640161098b565b8282516020840186f590506001600160a01b0381166125825760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f7900000000000000604482015260640161098b565b5f8181526001830160205260408120541515612582565b6001600160a01b038116610c6a576040517fb2335f2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612582836001600160a01b03841661309f565b5f6001600160a01b037f0000000000000000000000009700a405aff956f0baafc0a7ec57b71e656d5d9b16300361295257507f3b8b4d5d95ce9331e159bd99ef8b330912439a3c6b9f6cc6241bdf7cc832efb290565b610d72604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527ff7ed480d14d7cadb3ad6dbcc2c4119a0157b6265131b813624d0d68441359159918101919091527f5715d4ea092500b0d453c59f592af8be4f75f952db5ab3f9652ab4a5e64d2f006060820152600160808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b606060ff8314612a1457612a0d836130eb565b9050610d08565b818054612a2090613d5d565b80601f0160208091040260200160405190810160405280929190818152602001828054612a4c90613d5d565b8015612a975780601f10612a6e57610100808354040283529160200191612a97565b820191905f5260205f20905b815481529060010190602001808311612a7a57829003601f168201915b50505050509050610d08565b5f610d08612aaf6128fc565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b5f805f612af78585613128565b91509150612b048161316a565b509392505050565b612b15816132ce565b610c6a576040517fd93f96330000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b6060615fb45f839003612b8d576040517f3a67a86400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81612b9a60018661426e565b612ba49190614281565b612baf906001614294565b90508067ffffffffffffffff811115612bca57612bca613a63565b604051908082528060200260200182016040528015612bf3578160200160208202803683370190505b5092505f5b81811015612ca1575f612c0b84836142a7565b90505f612c188583614294565b905086811115612c255750855b612c6d612c3482848a8c6142be565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061332692505050565b868481518110612c7f57612c7f613de1565b6001600160a01b03909216602092830291909101909101525050600101612bf8565b50505092915050565b5f612582836001600160a01b038416612f5f565b612cc7816116d3565b15612d01576040517fd0bdb3ae0000000000000000000000000000000000000000000000000000000081526004810182905260240161098b565b612d0c60068261306b565b15610c6a5760405181907f20352ef9ad91057d3267998ab4fb71a6f13a6c130dd2ad17d7a79c859af6d70c905f90a250565b5f828152600560209081526040808320848452909152902054839003612d6357505050565b5f82815260056020908152604080832084845290915290205415612da457604051630ed1518b60e11b8152600481018390526024810182905260440161098b565b5f828152600560209081526040808320848452909152808220859055518291849186917f38ba0ee63038c97028a7faa932f9f0231f37310fe7ded293204b9c7da39d69c791a46117a8828261336c565b6060813b80612e0a576311052bb45f526004601cfd5b600181039050604051915061ffe0603f82011682016040528082525f8160208401015280600160208401853c50919050565b6040515f5b82811a15612e5157600101612e41565b808252602082018381525f82820152505060408101604052919050565b5f61258283835f613410565b805160218110612e915763ec92f9a35f526004601cfd5b9081015160209190910360031b1b90565b60608351828111612eb1578092505b838111612ebc578093505b5081831015612582575060405182820380825293830193601f19601f820181165b8681015184820152810180612edd57505f83830160200152603f9091011681016040529392505050565b6060815f01805480602002602001604051908101604052809291908181526020018280548015610ecd57602002820191905f5260205f20905b815481526020019060010190808311612f405750505050509050919050565b5f8181526001830160205260408120548015613039575f612f8160018361426e565b85549091505f90612f949060019061426e565b9050818114612ff3575f865f018281548110612fb257612fb2613de1565b905f5260205f200154905080875f018481548110612fd257612fd2613de1565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080613004576130046142e5565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610d08565b5f915050610d08565b5f610d0861304f83612e3c565b6134df565b5f8115801590610d085750610d0861304f83612e3c565b5f612582838361309f565b5f604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b5f8181526001830160205260408120546130e457508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610d08565b505f610d08565b60605f6130f7836134fa565b6040805160208082528183019092529192505f91906020820181803683375050509182525060208101929092525090565b5f80825160410361315c576020830151604084015160608501515f1a6131508782858561353a565b94509450505050613163565b505f905060025b9250929050565b5f81600481111561317d5761317d6142f9565b036131855750565b6001816004811115613199576131996142f9565b036131e65760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161098b565b60028160048111156131fa576131fa6142f9565b036132475760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161098b565b600381600481111561325b5761325b6142f9565b03610c6a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f7565000000000000000000000000000000000000000000000000000000000000606482015260840161098b565b5f806132d98361250d565b90506132e481613054565b6132f057505f92915050565b5f6132fa846135f7565b905061330581613042565b61331257505f9392505050565b61331c828261365d565b9093149392505050565b5f8151600181018060401b6bfd61000080600a3d393df3001761ffff8211850152600a8101601585015ff0925050816133665763301164255f526004601cfd5b90915290565b5f828152600f60205260409020600181015482111561338d57600181018290555b5f61339783612594565b5f8181526002840160205260409020549091508311156133c4575f81815260028301602052604090208390555b5f6133ce846125aa565b5f8181526003850160205260409020549091508411156133fb575f81815260038401602052604090208490555b613408600484018561306b565b505050505050565b5f835183516134305780831161342857829150612b04565b809150612b04565b8351602086015f19935084810196506001828483010301601f831660200360031b6020880151858810838b101661346b575050505050612b04565b602085106134b0578460208a01205b818b5118831c6134975780868c200361349757848b0397506134a5565b60018b019a50838b1061347a575b505050505050612b04565b808a5118821c6134c457838a0396506134d2565b60018a019950828a106134b0575b5050505050509392505050565b5f610d08826f07fffffe87fffffe03ff0000000000006136a6565b5f60ff8216601f811115610d08576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561356f57505f905060036135ee565b604080515f8082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156135c0573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b0381166135e8575f600192509250506135ee565b91505f90505b94509492505050565b5f8061360283612e3c565b90505f613632604051806040016040528060028152602001611d1d60f11b81525083612e6e90919063ffffffff16565b90505f19810361364557505f9392505050565b61255b612571613656836002614294565b84906136df565b5f81810361366c575081610d08565b61258261367884612e3c565b61368184612e3c565b60405160200161369292919061430d565b604051602081830303815290604052612e7a565b815160019015610d08578160801b60801c60208401845181015b8282515f1a1c84169350600182019150808210841615612ca1576136c0565b606061258283835f19612ea2565b828054828255905f5260205f20908101928215613740579160200282015b8281111561374057825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061370b565b5061374c929150613783565b5090565b50805461375c90613d5d565b5f825580601f1061376b575050565b601f0160209004905f5260205f2090810190610c6a91905b5b8082111561374c575f8155600101613784565b5f602082840312156137a7575f80fd5b5035919050565b5f5b838110156137c85781810151838201526020016137b0565b50505f910152565b5f81518084526137e78160208601602086016137ae565b601f01601f19169290920160200192915050565b6020815281516020820152602082015160408201525f604083015160c0606084015261382a60e08401826137d0565b90506001600160a01b0360608501511660808401526080840151601f19808584030160a086015261385b83836137d0565b925060a08601519150808584030160c08601525061387982826137d0565b95945050505050565b5f60208284031215613892575f80fd5b813567ffffffffffffffff8111156138a8575f80fd5b820160c08185031215612582575f80fd5b5f80604083850312156138ca575f80fd5b82359150602083013567ffffffffffffffff8111156138e7575f80fd5b8301606081860312156138f8575f80fd5b809150509250929050565b5f8060408385031215613914575f80fd5b50508035926020909101359150565b602080825282518282018190525f9190848201906040850190845b8181101561395a5783518352928401929184019160010161393e565b50909695505050505050565b6001600160a01b0381168114610c6a575f80fd5b5f806040838503121561398b575f80fd5b823561399681613966565b946020939093013593505050565b5f602082840312156139b4575f80fd5b813561258281613966565b602081525f61258260208301846137d0565b6001600160a01b0381511682525f6020820151606060208501526139f860608501826137d0565b90506040830151848203604086015261387982826137d0565b602081525f61258260208301846139d1565b602080825282518282018190525f9190848201906040850190845b8181101561395a5783516001600160a01b031683529284019291840191600101613a3e565b634e487b7160e01b5f52604160045260245ffd5b5f67ffffffffffffffff80841115613a9157613a91613a63565b604051601f8501601f19908116603f01168101908282118183101715613ab957613ab9613a63565b81604052809350858152868686011115613ad1575f80fd5b858560208301375f602087830101525050509392505050565b5f82601f830112613af9575f80fd5b61258283833560208501613a77565b5f805f8060808587031215613b1b575f80fd5b8435935060208501359250604085013567ffffffffffffffff811115613b3f575f80fd5b613b4b87828801613aea565b949793965093946060013593505050565b5f8060408385031215613b6d575f80fd5b8235613b7881613966565b9150602083013567ffffffffffffffff811115613b93575f80fd5b8301601f81018513613ba3575f80fd5b613bb285823560208401613a77565b9150509250929050565b5f815180845260208085019450602084015f5b83811015613beb57815187529582019590820190600101613bcf565b509495945050505050565b7fff000000000000000000000000000000000000000000000000000000000000008816815260e060208201525f613c3060e08301896137d0565b8281036040840152613c4281896137d0565b90508660608401526001600160a01b03861660808401528460a084015282810360c0840152613c718185613bbc565b9a9950505050505050505050565b602081525f6125826020830184613bbc565b5f60208083016020845280855180835260408601915060408160051b8701019250602087015f5b82811015613ce657603f19888603018452613cd48583516139d1565b94509285019290850190600101613cb8565b5092979650505050505050565b5f805f805f60a08688031215613d07575f80fd5b8535945060208601359350604086013567ffffffffffffffff811115613d2b575f80fd5b613d3788828901613aea565b935050606086013591506080860135613d4f81613966565b809150509295509295909350565b600181811c90821680613d7157607f821691505b60208210810361250757634e487b7160e01b5f52602260045260245ffd5b5f808335601e19843603018112613da4575f80fd5b83018035915067ffffffffffffffff821115613dbe575f80fd5b602001915036819003821315613163575f80fd5b818382375f9101908152919050565b634e487b7160e01b5f52603260045260245ffd5b5f8351613e068184602088016137ae565b835190830190613e1a8183602088016137ae565b01949350505050565b5f60208284031215613e33575f80fd5b5051919050565b6001600160a01b0383168152604060208201525f61255b60408301846137d0565b601f8211156117a857805f5260205f20601f840160051c81016020851015613e805750805b601f840160051c820191505b81811015610c65575f8155600101613e8c565b815167ffffffffffffffff811115613eb957613eb9613a63565b613ecd81613ec78454613d5d565b84613e5b565b602080601f831160018114613f00575f8415613ee95750858301515b5f19600386901b1c1916600185901b178555613408565b5f85815260208120601f198616915b82811015613f2e57888601518255948401946001909101908401613f0f565b5085821015613f4b57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f808354613f6881613d5d565b60018281168015613f805760018114613f9557613fc1565b60ff1984168752821515830287019450613fc1565b875f526020805f205f5b85811015613fb85781548a820152908401908201613f9f565b50505082870194505b50929695505050505050565b67ffffffffffffffff831115613fe557613fe5613a63565b613ff983613ff38354613d5d565b83613e5b565b5f601f84116001811461402a575f85156140135750838201355b5f19600387901b1c1916600186901b178355610c65565b5f83815260208120601f198716915b828110156140595786850135825560209485019460019092019101614039565b5086821015614075575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b813561409281613966565b6001600160a01b0381166001600160a01b031983541617825550600180820160206140c06020860186613d8f565b67ffffffffffffffff8111156140d8576140d8613a63565b6140ec816140e68654613d5d565b86613e5b565b5f601f82116001811461411d575f83156141065750838201355b5f19600385901b1c1916600184901b178655614171565b5f86815260208120601f198516915b82811015614149578685013582559387019390890190870161412c565b5084821015614165575f1960f88660031b161c19848701351681555b505060018360011b0186555b505050505050506141856040830183613d8f565b614193818360028601613fcd565b50505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b604081525f6141d4604083018688614199565b82810360208401526141e7818587614199565b979650505050505050565b6001600160a01b0386168152606060208201525f614214606083018688614199565b8281036040840152614227818587614199565b98975050505050505050565b634e487b7160e01b5f52601260045260245ffd5b5f8261425557614255614233565b500690565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610d0857610d0861425a565b5f8261428f5761428f614233565b500490565b80820180821115610d0857610d0861425a565b8082028115828204841417610d0857610d0861425a565b5f80858511156142cc575f80fd5b838611156142d8575f80fd5b5050820193919092039150565b634e487b7160e01b5f52603160045260245ffd5b634e487b7160e01b5f52602160045260245ffd5b5f835161431e8184602088016137ae565b611d1d60f11b908301908152835161433d8160028401602088016137ae565b0160020194935050505056fea164736f6c6343000817000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000018d162c462981662D76ebe1Be8aB24ad317d04f8
-----Decoded View---------------
Arg [0] : owner_ (address): 0x18d162c462981662D76ebe1Be8aB24ad317d04f8
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000018d162c462981662D76ebe1Be8aB24ad317d04f8
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ 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.