Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- AutomataDcapV3Attestation
- Optimization enabled
- true
- Compiler version
- v0.8.30+commit.73712a01
- Optimization runs
- 200
- EVM Version
- prague
- Verified at
- 2025-12-15T12:47:09.954371Z
contracts/layer1/automata-attestation/AutomataDcapV3Attestation.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import { IAttestation } from "./interfaces/IAttestation.sol";
import { ISigVerifyLib } from "./interfaces/ISigVerifyLib.sol";
import { EnclaveIdStruct } from "./lib/EnclaveIdStruct.sol";
import { PEMCertChainLib } from "./lib/PEMCertChainLib.sol";
import { V3Parser } from "./lib/QuoteV3Auth/V3Parser.sol";
import { V3Struct } from "./lib/QuoteV3Auth/V3Struct.sol";
import { TCBInfoStruct } from "./lib/TCBInfoStruct.sol";
import { IPEMCertChainLib } from "./lib/interfaces/IPEMCertChainLib.sol";
import { BytesUtils } from "./utils/BytesUtils.sol";
import { EfficientHashLib } from "solady/src/utils/EfficientHashLib.sol";
import { LibString } from "solady/src/utils/LibString.sol";
import { EssentialContract } from "src/shared/common/EssentialContract.sol";
import "./AutomataDcapV3Attestation_Layout.sol"; // DO NOT DELETE
/// @title AutomataDcapV3Attestation
/// @custom:security-contact security@taiko.xyz
contract AutomataDcapV3Attestation is IAttestation, EssentialContract {
using BytesUtils for bytes;
// https://github.com/intel/SGXDataCenterAttestationPrimitives/blob/e7604e02331b3377f3766ed3653250e03af72d45/QuoteVerification/QVL/Src/AttestationLibrary/src/CertVerification/X509Constants.h#L64
uint256 internal constant CPUSVN_LENGTH = 16;
// keccak256(hex"0ba9c4c0c0c86193a3fe23d6b02cda10a8bbd4e88e48b4458561a36e705525f567918e2edc88e40d860bd0cc4ee26aacc988e505a953558c453f6b0904ae7394")
// the uncompressed (0x04) prefix is not included in the pubkey pre-image
bytes32 internal constant ROOTCA_PUBKEY_HASH =
0x89f72d7c488e5b53a77c23ebcb36970ef7eb5bcf6658e9b8292cfbe4703a8473;
uint8 internal constant INVALID_EXIT_CODE = 255;
ISigVerifyLib public sigVerifyLib; // slot 1
IPEMCertChainLib public pemCertLib; // slot 2
bool public checkLocalEnclaveReport; // slot 3
mapping(bytes32 enclave => bool trusted) public trustedUserMrEnclave; // slot 4
mapping(bytes32 signer => bool trusted) public trustedUserMrSigner; // slot 5
// Quote Collateral Configuration
// Index definition:
// 0 = Quote PCKCrl
// 1 = RootCrl
mapping(uint256 idx => mapping(bytes serialNum => bool revoked)) public serialNumIsRevoked; // slot
// 6
// fmspc => tcbInfo
mapping(string fmspc => TCBInfoStruct.TCBInfo tcbInfo) public tcbInfo; // slot 7
EnclaveIdStruct.EnclaveId public qeIdentity; // takes 4 slots, slot 8,9,10,11
uint256[39] __gap;
event MrSignerUpdated(bytes32 indexed mrSigner, bool trusted);
event MrEnclaveUpdated(bytes32 indexed mrEnclave, bool trusted);
event TcbInfoJsonConfigured(string indexed fmspc, TCBInfoStruct.TCBInfo tcbInfoInput);
event QeIdentityConfigured(EnclaveIdStruct.EnclaveId qeIdentityInput);
event LocalReportCheckToggled(bool checkLocalEnclaveReport);
event RevokedCertSerialNumAdded(uint256 indexed index, bytes serialNum);
event RevokedCertSerialNumRemoved(uint256 indexed index, bytes serialNum);
// @notice Initializes the contract.
/// @param sigVerifyLibAddr Address of the signature verification library.
/// @param pemCertLibAddr Address of certificate library.
function init(
address owner,
address sigVerifyLibAddr,
address pemCertLibAddr
)
external
initializer
{
__Essential_init(owner);
sigVerifyLib = ISigVerifyLib(sigVerifyLibAddr);
pemCertLib = PEMCertChainLib(pemCertLibAddr);
}
function setMrSigner(bytes32 _mrSigner, bool _trusted) external onlyOwner {
trustedUserMrSigner[_mrSigner] = _trusted;
emit MrSignerUpdated(_mrSigner, _trusted);
}
function setMrEnclave(bytes32 _mrEnclave, bool _trusted) external onlyOwner {
trustedUserMrEnclave[_mrEnclave] = _trusted;
emit MrEnclaveUpdated(_mrEnclave, _trusted);
}
function addRevokedCertSerialNum(
uint256 index,
bytes[] calldata serialNumBatch
)
external
onlyOwner
{
uint256 size = serialNumBatch.length;
for (uint256 i; i < size; ++i) {
if (serialNumIsRevoked[index][serialNumBatch[i]]) {
continue;
}
serialNumIsRevoked[index][serialNumBatch[i]] = true;
emit RevokedCertSerialNumAdded(index, serialNumBatch[i]);
}
}
function removeRevokedCertSerialNum(
uint256 index,
bytes[] calldata serialNumBatch
)
external
onlyOwner
{
uint256 size = serialNumBatch.length;
for (uint256 i; i < size; ++i) {
if (!serialNumIsRevoked[index][serialNumBatch[i]]) {
continue;
}
delete serialNumIsRevoked[index][serialNumBatch[i]];
emit RevokedCertSerialNumRemoved(index, serialNumBatch[i]);
}
}
function configureTcbInfoJson(
string calldata fmspc,
TCBInfoStruct.TCBInfo calldata tcbInfoInput
)
public
onlyOwner
{
// 2.2M gas
tcbInfo[fmspc] = tcbInfoInput;
emit TcbInfoJsonConfigured(fmspc, tcbInfoInput);
}
function configureQeIdentityJson(EnclaveIdStruct.EnclaveId calldata qeIdentityInput)
external
onlyOwner
{
// 250k gas
qeIdentity = qeIdentityInput;
emit QeIdentityConfigured(qeIdentityInput);
}
function toggleLocalReportCheck() external onlyOwner {
checkLocalEnclaveReport = !checkLocalEnclaveReport;
emit LocalReportCheckToggled(checkLocalEnclaveReport);
}
function _attestationTcbIsValid(TCBInfoStruct.TCBStatus status)
internal
pure
virtual
returns (bool valid)
{
return status == TCBInfoStruct.TCBStatus.OK
|| status == TCBInfoStruct.TCBStatus.TCB_SW_HARDENING_NEEDED
|| status == TCBInfoStruct.TCBStatus.TCB_CONFIGURATION_AND_SW_HARDENING_NEEDED
|| status == TCBInfoStruct.TCBStatus.TCB_OUT_OF_DATE
|| status == TCBInfoStruct.TCBStatus.TCB_OUT_OF_DATE_CONFIGURATION_NEEDED;
}
function verifyAttestation(bytes calldata data) external view override returns (bool success) {
(success,) = _verify(data);
}
/// @dev Provide the raw quote binary as input
/// @dev The attestation data (or the returned data of this method)
/// is constructed depending on the validity of the quote verification.
/// @dev After confirming that a quote has been verified, the attestation's validity then
/// depends on the
/// status of the associated TCB.
/// @dev Example scenarios as below:
/// --------------------------------
/// @dev Invalid quote verification: returns (false, INVALID_EXIT_CODE)
///
/// @dev For all valid quote verification, the validity of the attestation depends on the status
/// of a
/// matching TCBInfo and this is defined in the _attestationTcbIsValid() method, which can be
/// overwritten
/// in derived contracts. (Except for "Revoked" status, which also returns (false,
/// INVALID_EXIT_CODE) value)
/// @dev For all valid quote verification, returns the following data:
/// (_attestationTcbIsValid(), abi.encodePacked(sha256(quote), uint8 exitCode))
/// @dev exitCode is defined in the {{ TCBInfoStruct.TCBStatus }} enum
function _verify(bytes calldata quote) private view returns (bool, bytes memory) {
bytes memory retData = abi.encodePacked(INVALID_EXIT_CODE);
// Step 1: Parse the quote input = 152k gas
(bool successful, V3Struct.ParsedV3QuoteStruct memory parsedV3Quote) =
V3Parser.parseInput(quote, address(pemCertLib));
if (!successful) {
return (false, retData);
}
return _verifyParsedQuote(parsedV3Quote);
}
function _verifyQEReportWithIdentity(V3Struct.EnclaveReport memory quoteEnclaveReport)
private
view
returns (bool, EnclaveIdStruct.EnclaveIdStatus status)
{
EnclaveIdStruct.EnclaveId memory enclaveId = qeIdentity;
bool miscselectMatched =
quoteEnclaveReport.miscSelect & enclaveId.miscselectMask == enclaveId.miscselect;
bool attributesMatched =
quoteEnclaveReport.attributes & enclaveId.attributesMask == enclaveId.attributes;
bool mrsignerMatched = quoteEnclaveReport.mrSigner == enclaveId.mrsigner;
bool isvprodidMatched = quoteEnclaveReport.isvProdId == enclaveId.isvprodid;
bool tcbFound;
uint256 size = enclaveId.tcbLevels.length;
for (uint256 i; i < size; ++i) {
EnclaveIdStruct.TcbLevel memory tcb = enclaveId.tcbLevels[i];
if (tcb.tcb.isvsvn <= quoteEnclaveReport.isvSvn) {
tcbFound = true;
status = tcb.tcbStatus;
break;
}
}
return (
miscselectMatched && attributesMatched && mrsignerMatched && isvprodidMatched
&& tcbFound,
status
);
}
function _checkTcbLevels(
IPEMCertChainLib.PCKCertificateField memory pck,
TCBInfoStruct.TCBInfo memory tcb
)
private
pure
returns (bool, TCBInfoStruct.TCBStatus status)
{
uint256 size = tcb.tcbLevels.length;
for (uint256 i; i < size; ++i) {
TCBInfoStruct.TCBLevelObj memory current = tcb.tcbLevels[i];
bool pceSvnIsHigherOrGreater = pck.sgxExtension.pcesvn >= current.pcesvn;
bool cpuSvnsAreHigherOrGreater = _isCpuSvnHigherOrGreater(
pck.sgxExtension.sgxTcbCompSvnArr, current.sgxTcbCompSvnArr
);
if (pceSvnIsHigherOrGreater && cpuSvnsAreHigherOrGreater) {
status = current.status;
bool tcbIsRevoked = status == TCBInfoStruct.TCBStatus.TCB_REVOKED;
return (!tcbIsRevoked, status);
}
}
return (true, TCBInfoStruct.TCBStatus.TCB_UNRECOGNIZED);
}
function _isCpuSvnHigherOrGreater(
uint256[] memory pckCpuSvns,
uint8[] memory tcbCpuSvns
)
private
pure
returns (bool)
{
if (pckCpuSvns.length != CPUSVN_LENGTH || tcbCpuSvns.length != CPUSVN_LENGTH) {
return false;
}
for (uint256 i; i < CPUSVN_LENGTH; ++i) {
if (pckCpuSvns[i] < tcbCpuSvns[i]) {
return false;
}
}
return true;
}
function _verifyCertChain(IPEMCertChainLib.ECSha256Certificate[] memory certs)
private
view
returns (bool)
{
uint256 n = certs.length;
bool certRevoked;
bool certNotExpired;
bool verified;
bool certChainCanBeTrusted;
for (uint256 i; i < n; ++i) {
IPEMCertChainLib.ECSha256Certificate memory issuer;
if (i == n - 1) {
// rootCA
issuer = certs[i];
} else {
issuer = certs[i + 1];
if (i == n - 2) {
// this cert is expected to be signed by the root
certRevoked = serialNumIsRevoked[
uint256(IPEMCertChainLib.CRL.ROOT)
][certs[i].serialNumber];
} else if (certs[i].isPck) {
certRevoked = serialNumIsRevoked[
uint256(IPEMCertChainLib.CRL.PCK)
][certs[i].serialNumber];
}
if (certRevoked) {
break;
}
}
certNotExpired =
block.timestamp > certs[i].notBefore && block.timestamp < certs[i].notAfter;
if (!certNotExpired) {
break;
}
verified = sigVerifyLib.verifyES256Signature(
certs[i].tbsCertificate, certs[i].signature, issuer.pubKey
);
if (!verified) {
break;
}
if (EfficientHashLib.hash(issuer.pubKey) == ROOTCA_PUBKEY_HASH) {
certChainCanBeTrusted = true;
break;
}
}
return !certRevoked && certNotExpired && verified && certChainCanBeTrusted;
}
function _enclaveReportSigVerification(
bytes memory pckCertPubKey,
bytes memory signedQuoteData,
V3Struct.ECDSAQuoteV3AuthData memory authDataV3,
V3Struct.EnclaveReport memory qeEnclaveReport
)
private
view
returns (bool)
{
bytes32 expectedAuthDataHash = bytes32(qeEnclaveReport.reportData.substring(0, 32));
bytes memory concatOfAttestKeyAndQeAuthData =
abi.encodePacked(authDataV3.ecdsaAttestationKey, authDataV3.qeAuthData.data);
bytes32 computedAuthDataHash = sha256(concatOfAttestKeyAndQeAuthData);
bool qeReportDataIsValid = expectedAuthDataHash == computedAuthDataHash;
if (qeReportDataIsValid) {
bytes memory pckSignedQeReportBytes =
V3Parser.packQEReport(authDataV3.pckSignedQeReport);
bool qeSigVerified = sigVerifyLib.verifyES256Signature(
pckSignedQeReportBytes, authDataV3.qeReportSignature, pckCertPubKey
);
bool quoteSigVerified = sigVerifyLib.verifyES256Signature(
signedQuoteData, authDataV3.ecdsa256BitSignature, authDataV3.ecdsaAttestationKey
);
return qeSigVerified && quoteSigVerified;
} else {
return false;
}
}
/// --------------- validate parsed quote ---------------
/// @dev Provide the parsed quote binary as input
/// @dev The attestation data (or the returned data of this method)
/// is constructed depending on the validity of the quote verification.
/// @dev After confirming that a quote has been verified, the attestation's validity then
/// depends on the
/// status of the associated TCB.
/// @dev Example scenarios as below:
/// --------------------------------
/// @dev Invalid quote verification: returns (false, INVALID_EXIT_CODE)
///
/// @dev For all valid quote verification, the validity of the attestation depends on the status
/// of a
/// matching TCBInfo and this is defined in the _attestationTcbIsValid() method, which can be
/// overwritten
/// in derived contracts. (Except for "Revoked" status, which also returns (false,
/// INVALID_EXIT_CODE) value)
/// @dev For all valid quote verification, returns the following data:
/// (_attestationTcbIsValid())
/// @dev exitCode is defined in the {{ TCBInfoStruct.TCBStatus }} enum
function verifyParsedQuote(V3Struct.ParsedV3QuoteStruct calldata v3quote)
external
view
override
returns (bool, bytes memory)
{
return _verifyParsedQuote(v3quote);
}
function _verifyParsedQuote(V3Struct.ParsedV3QuoteStruct memory v3quote)
internal
view
returns (bool, bytes memory)
{
bytes memory retData = abi.encodePacked(INVALID_EXIT_CODE);
// // Step 1: Parse the quote input = 152k gas
(
bool successful,,,
bytes memory signedQuoteData,
V3Struct.ECDSAQuoteV3AuthData memory authDataV3
) = V3Parser.validateParsedInput(v3quote);
if (!successful) {
return (false, retData);
}
// Step 2: Verify application enclave report MRENCLAVE and MRSIGNER
{
if (checkLocalEnclaveReport) {
// 4k gas
bool mrEnclaveIsTrusted = trustedUserMrEnclave[v3quote.localEnclaveReport.mrEnclave];
bool mrSignerIsTrusted = trustedUserMrSigner[v3quote.localEnclaveReport.mrSigner];
if (!mrEnclaveIsTrusted || !mrSignerIsTrusted) {
return (false, retData);
}
}
}
// Step 3: Verify enclave identity = 43k gas
EnclaveIdStruct.EnclaveIdStatus qeTcbStatus;
{
bool verifiedEnclaveIdSuccessfully;
(verifiedEnclaveIdSuccessfully, qeTcbStatus) =
_verifyQEReportWithIdentity(v3quote.v3AuthData.pckSignedQeReport);
if (!verifiedEnclaveIdSuccessfully) {
return (false, retData);
}
if (
!verifiedEnclaveIdSuccessfully
|| qeTcbStatus
== EnclaveIdStruct.EnclaveIdStatus.SGX_ENCLAVE_REPORT_ISVSVN_REVOKED
) {
return (false, retData);
}
}
// Step 4: Parse Quote CertChain
IPEMCertChainLib.ECSha256Certificate[] memory parsedQuoteCerts;
TCBInfoStruct.TCBInfo memory fetchedTcbInfo;
{
// 536k gas
parsedQuoteCerts = new IPEMCertChainLib.ECSha256Certificate[](3);
for (uint256 i; i < 3; ++i) {
bool isPckCert = i == 0; // additional parsing for PCKCert
bool certDecodedSuccessfully;
// TODO(Yue): move decodeCert offchain
(certDecodedSuccessfully, parsedQuoteCerts[i]) = pemCertLib.decodeCert(
authDataV3.certification.decodedCertDataArray[i], isPckCert
);
if (!certDecodedSuccessfully) {
return (false, retData);
}
}
}
// Step 5: basic PCK and TCB check = 381k gas
{
string memory parsedFmspc = parsedQuoteCerts[0].pck.sgxExtension.fmspc;
fetchedTcbInfo = tcbInfo[parsedFmspc];
bool tcbConfigured = LibString.eq(parsedFmspc, fetchedTcbInfo.fmspc);
if (!tcbConfigured) {
return (false, retData);
}
IPEMCertChainLib.ECSha256Certificate memory pckCert = parsedQuoteCerts[0];
bool pceidMatched = LibString.eq(pckCert.pck.sgxExtension.pceid, fetchedTcbInfo.pceid);
if (!pceidMatched) {
return (false, retData);
}
}
// Step 6: Verify TCB Level
TCBInfoStruct.TCBStatus tcbStatus;
{
// 4k gas
bool tcbVerified;
(tcbVerified, tcbStatus) = _checkTcbLevels(parsedQuoteCerts[0].pck, fetchedTcbInfo);
if (!tcbVerified) {
return (false, retData);
}
}
// Step 7: Verify cert chain for PCK
{
// 660k gas (rootCA pubkey is trusted)
bool pckCertChainVerified = _verifyCertChain(parsedQuoteCerts);
if (!pckCertChainVerified) {
return (false, retData);
}
}
// Step 8: Verify the local attestation sig and qe report sig = 670k gas
{
bool enclaveReportSigsVerified = _enclaveReportSigVerification(
parsedQuoteCerts[0].pubKey,
signedQuoteData,
authDataV3,
v3quote.v3AuthData.pckSignedQeReport
);
if (!enclaveReportSigsVerified) {
return (false, retData);
}
}
retData = abi.encodePacked(sha256(abi.encode(v3quote)), tcbStatus);
return (_attestationTcbIsValid(tcbStatus), retData);
}
}
node_modules/solady/src/utils/EfficientHashLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for efficiently performing keccak256 hashes.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EfficientHashLib.sol)
/// @dev To avoid stack-too-deep, you can use:
/// ```
/// bytes32[] memory buffer = EfficientHashLib.malloc(10);
/// EfficientHashLib.set(buffer, 0, value0);
/// ..
/// EfficientHashLib.set(buffer, 9, value9);
/// bytes32 finalHash = EfficientHashLib.hash(buffer);
/// ```
library EfficientHashLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MALLOC-LESS HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `keccak256(abi.encode(v0))`.
function hash(bytes32 v0) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, v0)
result := keccak256(0x00, 0x20)
}
}
/// @dev Returns `keccak256(abi.encode(v0))`.
function hash(uint256 v0) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, v0)
result := keccak256(0x00, 0x20)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1))`.
function hash(bytes32 v0, bytes32 v1) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, v0)
mstore(0x20, v1)
result := keccak256(0x00, 0x40)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1))`.
function hash(uint256 v0, uint256 v1) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, v0)
mstore(0x20, v1)
result := keccak256(0x00, 0x40)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1, v2))`.
function hash(bytes32 v0, bytes32 v1, bytes32 v2) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
result := keccak256(m, 0x60)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1, v2))`.
function hash(uint256 v0, uint256 v1, uint256 v2) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
result := keccak256(m, 0x60)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1, v2, v3))`.
function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
result := keccak256(m, 0x80)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1, v2, v3))`.
function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
result := keccak256(m, 0x80)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v4))`.
function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3, bytes32 v4)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
result := keccak256(m, 0xa0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v4))`.
function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3, uint256 v4)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
result := keccak256(m, 0xa0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v5))`.
function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3, bytes32 v4, bytes32 v5)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
result := keccak256(m, 0xc0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v5))`.
function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3, uint256 v4, uint256 v5)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
result := keccak256(m, 0xc0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v6))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
result := keccak256(m, 0xe0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v6))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
result := keccak256(m, 0xe0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v7))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
result := keccak256(m, 0x100)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v7))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
result := keccak256(m, 0x100)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v8))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
result := keccak256(m, 0x120)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v8))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
result := keccak256(m, 0x120)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v9))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
result := keccak256(m, 0x140)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v9))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
result := keccak256(m, 0x140)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v10))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9,
bytes32 v10
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
result := keccak256(m, 0x160)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v10))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9,
uint256 v10
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
result := keccak256(m, 0x160)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v11))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9,
bytes32 v10,
bytes32 v11
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
result := keccak256(m, 0x180)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v11))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9,
uint256 v10,
uint256 v11
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
result := keccak256(m, 0x180)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v12))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9,
bytes32 v10,
bytes32 v11,
bytes32 v12
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
mstore(add(m, 0x180), v12)
result := keccak256(m, 0x1a0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v12))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9,
uint256 v10,
uint256 v11,
uint256 v12
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
mstore(add(m, 0x180), v12)
result := keccak256(m, 0x1a0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v13))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9,
bytes32 v10,
bytes32 v11,
bytes32 v12,
bytes32 v13
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
mstore(add(m, 0x180), v12)
mstore(add(m, 0x1a0), v13)
result := keccak256(m, 0x1c0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v13))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9,
uint256 v10,
uint256 v11,
uint256 v12,
uint256 v13
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
mstore(add(m, 0x180), v12)
mstore(add(m, 0x1a0), v13)
result := keccak256(m, 0x1c0)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTES32 BUFFER HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `keccak256(abi.encode(buffer[0], .., buffer[buffer.length - 1]))`.
function hash(bytes32[] memory buffer) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := keccak256(add(buffer, 0x20), shl(5, mload(buffer)))
}
}
/// @dev Sets `buffer[i]` to `value`, without a bounds check.
/// Returns the `buffer` for function chaining.
function set(bytes32[] memory buffer, uint256 i, bytes32 value)
internal
pure
returns (bytes32[] memory)
{
/// @solidity memory-safe-assembly
assembly {
mstore(add(buffer, shl(5, add(1, i))), value)
}
return buffer;
}
/// @dev Sets `buffer[i]` to `value`, without a bounds check.
/// Returns the `buffer` for function chaining.
function set(bytes32[] memory buffer, uint256 i, uint256 value)
internal
pure
returns (bytes32[] memory)
{
/// @solidity memory-safe-assembly
assembly {
mstore(add(buffer, shl(5, add(1, i))), value)
}
return buffer;
}
/// @dev Returns `new bytes32[](n)`, without zeroing out the memory.
function malloc(uint256 n) internal pure returns (bytes32[] memory buffer) {
/// @solidity memory-safe-assembly
assembly {
buffer := mload(0x40)
mstore(buffer, n)
mstore(0x40, add(shl(5, add(1, n)), buffer))
}
}
/// @dev Frees memory that has been allocated for `buffer`.
/// No-op if `buffer.length` is zero, or if new memory has been allocated after `buffer`.
function free(bytes32[] memory buffer) internal pure {
/// @solidity memory-safe-assembly
assembly {
let n := mload(buffer)
mstore(shl(6, lt(iszero(n), eq(add(shl(5, add(1, n)), buffer), mload(0x40)))), buffer)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EQUALITY CHECKS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `a == abi.decode(b, (bytes32))`.
function eq(bytes32 a, bytes memory b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := and(eq(0x20, mload(b)), eq(a, mload(add(b, 0x20))))
}
}
/// @dev Returns `abi.decode(a, (bytes32)) == a`.
function eq(bytes memory a, bytes32 b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := and(eq(0x20, mload(a)), eq(b, mload(add(a, 0x20))))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE SLICE HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the keccak256 of the slice from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function hash(bytes memory b, uint256 start, uint256 end)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(b)
end := xor(end, mul(xor(end, n), lt(n, end)))
start := xor(start, mul(xor(start, n), lt(n, start)))
result := keccak256(add(add(b, 0x20), start), mul(gt(end, start), sub(end, start)))
}
}
/// @dev Returns the keccak256 of the slice from `start` to the end of the bytes.
function hash(bytes memory b, uint256 start) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let n := mload(b)
start := xor(start, mul(xor(start, n), lt(n, start)))
result := keccak256(add(add(b, 0x20), start), mul(gt(n, start), sub(n, start)))
}
}
/// @dev Returns the keccak256 of the bytes.
function hash(bytes memory b) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := keccak256(add(b, 0x20), mload(b))
}
}
/// @dev Returns the keccak256 of the slice from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function hashCalldata(bytes calldata b, uint256 start, uint256 end)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
end := xor(end, mul(xor(end, b.length), lt(b.length, end)))
start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
let n := mul(gt(end, start), sub(end, start))
calldatacopy(mload(0x40), add(b.offset, start), n)
result := keccak256(mload(0x40), n)
}
}
/// @dev Returns the keccak256 of the slice from `start` to the end of the bytes.
function hashCalldata(bytes calldata b, uint256 start) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
let n := mul(gt(b.length, start), sub(b.length, start))
calldatacopy(mload(0x40), add(b.offset, start), n)
result := keccak256(mload(0x40), n)
}
}
/// @dev Returns the keccak256 of the bytes.
function hashCalldata(bytes calldata b) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
calldatacopy(mload(0x40), b.offset, b.length)
result := keccak256(mload(0x40), b.length)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SHA2-256 HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `sha256(abi.encode(b))`. Yes, it's more efficient.
function sha2(bytes32 b) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, b)
result := mload(staticcall(gas(), 2, 0x00, 0x20, 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the slice from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function sha2(bytes memory b, uint256 start, uint256 end)
internal
view
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(b)
end := xor(end, mul(xor(end, n), lt(n, end)))
start := xor(start, mul(xor(start, n), lt(n, start)))
// forgefmt: disable-next-item
result := mload(staticcall(gas(), 2, add(add(b, 0x20), start),
mul(gt(end, start), sub(end, start)), 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the slice from `start` to the end of the bytes.
function sha2(bytes memory b, uint256 start) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let n := mload(b)
start := xor(start, mul(xor(start, n), lt(n, start)))
// forgefmt: disable-next-item
result := mload(staticcall(gas(), 2, add(add(b, 0x20), start),
mul(gt(n, start), sub(n, start)), 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the bytes.
function sha2(bytes memory b) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(staticcall(gas(), 2, add(b, 0x20), mload(b), 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the slice from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function sha2Calldata(bytes calldata b, uint256 start, uint256 end)
internal
view
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
end := xor(end, mul(xor(end, b.length), lt(b.length, end)))
start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
let n := mul(gt(end, start), sub(end, start))
calldatacopy(mload(0x40), add(b.offset, start), n)
result := mload(staticcall(gas(), 2, mload(0x40), n, 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the slice from `start` to the end of the bytes.
function sha2Calldata(bytes calldata b, uint256 start) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
let n := mul(gt(b.length, start), sub(b.length, start))
calldatacopy(mload(0x40), add(b.offset, start), n)
result := mload(staticcall(gas(), 2, mload(0x40), n, 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the bytes.
function sha2Calldata(bytes calldata b) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
calldatacopy(mload(0x40), b.offset, b.length)
result := mload(staticcall(gas(), 2, mload(0x40), b.length, 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
}
node_modules/solady/src/utils/LibBytes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for byte related operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol)
library LibBytes {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Goated bytes storage struct that totally MOGs, no cap, fr.
/// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af.
/// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
struct BytesStorage {
bytes32 _spacer;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the bytes.
uint256 internal constant NOT_FOUND = type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE STORAGE OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sets the value of the bytes storage `$` to `s`.
function set(BytesStorage storage $, bytes memory s) internal {
/// @solidity memory-safe-assembly
assembly {
let n := mload(s)
let packed := or(0xff, shl(8, n))
for { let i := 0 } 1 {} {
if iszero(gt(n, 0xfe)) {
i := 0x1f
packed := or(n, shl(8, mload(add(s, i))))
if iszero(gt(n, i)) { break }
}
let o := add(s, 0x20)
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
sstore(add(p, shr(5, i)), mload(add(o, i)))
i := add(i, 0x20)
if iszero(lt(i, n)) { break }
}
break
}
sstore($.slot, packed)
}
}
/// @dev Sets the value of the bytes storage `$` to `s`.
function setCalldata(BytesStorage storage $, bytes calldata s) internal {
/// @solidity memory-safe-assembly
assembly {
let packed := or(0xff, shl(8, s.length))
for { let i := 0 } 1 {} {
if iszero(gt(s.length, 0xfe)) {
i := 0x1f
packed := or(s.length, shl(8, shr(8, calldataload(s.offset))))
if iszero(gt(s.length, i)) { break }
}
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
sstore(add(p, shr(5, i)), calldataload(add(s.offset, i)))
i := add(i, 0x20)
if iszero(lt(i, s.length)) { break }
}
break
}
sstore($.slot, packed)
}
}
/// @dev Sets the value of the bytes storage `$` to the empty bytes.
function clear(BytesStorage storage $) internal {
delete $._spacer;
}
/// @dev Returns whether the value stored is `$` is the empty bytes "".
function isEmpty(BytesStorage storage $) internal view returns (bool) {
return uint256($._spacer) & 0xff == uint256(0);
}
/// @dev Returns the length of the value stored in `$`.
function length(BytesStorage storage $) internal view returns (uint256 result) {
result = uint256($._spacer);
/// @solidity memory-safe-assembly
assembly {
let n := and(0xff, result)
result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n))))
}
}
/// @dev Returns the value stored in `$`.
function get(BytesStorage storage $) internal view returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let o := add(result, 0x20)
let packed := sload($.slot)
let n := shr(8, packed)
for { let i := 0 } 1 {} {
if iszero(eq(or(packed, 0xff), packed)) {
mstore(o, packed)
n := and(0xff, packed)
i := 0x1f
if iszero(gt(n, i)) { break }
}
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
mstore(add(o, i), sload(add(p, shr(5, i))))
i := add(i, 0x20)
if iszero(lt(i, n)) { break }
}
break
}
mstore(result, n) // Store the length of the memory.
mstore(add(o, n), 0) // Zeroize the slot after the bytes.
mstore(0x40, add(add(o, n), 0x20)) // Allocate memory.
}
}
/// @dev Returns the uint8 at index `i`. If out-of-bounds, returns 0.
function uint8At(BytesStorage storage $, uint256 i) internal view returns (uint8 result) {
/// @solidity memory-safe-assembly
assembly {
for { let packed := sload($.slot) } 1 {} {
if iszero(eq(or(packed, 0xff), packed)) {
if iszero(gt(i, 0x1e)) {
result := byte(i, packed)
break
}
if iszero(gt(i, and(0xff, packed))) {
mstore(0x00, $.slot)
let j := sub(i, 0x1f)
result := byte(and(j, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, j))))
}
break
}
if iszero(gt(i, shr(8, packed))) {
mstore(0x00, $.slot)
result := byte(and(i, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, i))))
}
break
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTES OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
function replace(bytes memory subject, bytes memory needle, bytes memory replacement)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let needleLen := mload(needle)
let replacementLen := mload(replacement)
let d := sub(result, subject) // Memory difference.
let i := add(subject, 0x20) // Subject bytes pointer.
mstore(0x00, add(i, mload(subject))) // End of subject.
if iszero(gt(needleLen, mload(subject))) {
let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1)
let h := 0 // The hash of `needle`.
if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} {
let t := mload(i)
// Whether the first `needleLen % 32` bytes of `subject` and `needle` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, needleLen), h)) {
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
// Copy the `replacement` one word at a time.
for { let j := 0 } 1 {} {
mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j)))
j := add(j, 0x20)
if iszero(lt(j, replacementLen)) { break }
}
d := sub(add(d, replacementLen), needleLen)
if needleLen {
i := add(i, needleLen)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
}
let end := mload(0x00)
let n := add(sub(d, add(result, 0x20)), end)
// Copy the rest of the bytes one word at a time.
for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) }
let o := add(i, d)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(bytes memory subject, bytes memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
result := not(0) // Initialize to `NOT_FOUND`.
for { let subjectLen := mload(subject) } 1 {} {
if iszero(mload(needle)) {
result := from
if iszero(gt(from, subjectLen)) { break }
result := subjectLen
break
}
let needleLen := mload(needle)
let subjectStart := add(subject, 0x20)
subject := add(subjectStart, from)
let end := add(sub(add(subjectStart, subjectLen), needleLen), 1)
let m := shl(3, sub(0x20, and(needleLen, 0x1f)))
let s := mload(add(needle, 0x20))
if iszero(and(lt(subject, end), lt(from, subjectLen))) { break }
if iszero(lt(needleLen, 0x20)) {
for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
if eq(keccak256(subject, needleLen), 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 `needle` in `subject`,
/// needleing from left to right, starting from `from`. Optimized for byte needles.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOfByte(bytes memory subject, bytes1 needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
result := not(0) // Initialize to `NOT_FOUND`.
if gt(mload(subject), from) {
let start := add(subject, 0x20)
let end := add(start, mload(subject))
let m := div(not(0), 255) // `0x0101 ... `.
let h := mul(byte(0, needle), m) // Replicating needle mask.
m := not(shl(7, m)) // `0x7f7f ... `.
for { let i := add(start, from) } 1 {} {
let c := xor(mload(i), h) // Load 32-byte chunk and xor with mask.
c := not(or(or(add(and(c, m), m), c), m)) // Each needle byte will be `0x80`.
if c {
c := and(not(shr(shl(3, sub(end, i)), not(0))), c) // Truncate bytes past the end.
if c {
let r := shl(7, lt(0x8421084210842108cc6318c6db6d54be, c)) // Save bytecode.
r := or(shl(6, lt(0xffffffffffffffff, shr(r, c))), r)
// forgefmt: disable-next-item
result := add(sub(i, start), shr(3, xor(byte(and(0x1f, shr(byte(24,
mul(0x02040810204081, shr(r, c))), 0x8421084210842108cc6318c6db6d54be)),
0xc0c8c8d0c8e8d0d8c8e8e0e8d0d8e0f0c8d0e8d0e0e0d8f0d0d0e0d8f8f8f8f8), r)))
break
}
}
i := add(i, 0x20)
if iszero(lt(i, end)) { break }
}
}
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right. Optimized for byte needles.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOfByte(bytes memory subject, bytes1 needle)
internal
pure
returns (uint256 result)
{
return indexOfByte(subject, needle, 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) {
return indexOf(subject, needle, 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
result := not(0) // Initialize to `NOT_FOUND`.
let needleLen := mload(needle)
if gt(needleLen, mload(subject)) { break }
let w := result
let fromMax := sub(mload(subject), needleLen)
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(needle, 0x20), needleLen) } 1 {} {
if eq(keccak256(subject, needleLen), 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 `needle` in `subject`,
/// needleing from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(bytes memory subject, bytes memory needle)
internal
pure
returns (uint256)
{
return lastIndexOf(subject, needle, type(uint256).max);
}
/// @dev Returns true if `needle` is found in `subject`, false otherwise.
function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) {
return indexOf(subject, needle) != NOT_FOUND;
}
/// @dev Returns whether `subject` starts with `needle`.
function startsWith(bytes memory subject, bytes memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(needle)
// Just using keccak256 directly is actually cheaper.
let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n))
result := lt(gt(n, mload(subject)), t)
}
}
/// @dev Returns whether `subject` ends with `needle`.
function endsWith(bytes memory subject, bytes memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(needle)
let notInRange := gt(n, mload(subject))
// `subject + 0x20 + max(subject.length - needle.length, 0)`.
let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n)))
// Just using keccak256 directly is actually cheaper.
result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange)
}
}
/// @dev Returns `subject` repeated `times`.
function repeat(bytes memory subject, uint256 times)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
let l := mload(subject) // Subject length.
if iszero(or(iszero(times), iszero(l))) {
result := mload(0x40)
subject := add(subject, 0x20)
let o := add(result, 0x20)
for {} 1 {} {
// Copy the `subject` one word at a time.
for { let j := 0 } 1 {} {
mstore(add(o, j), mload(add(subject, j)))
j := add(j, 0x20)
if iszero(lt(j, l)) { break }
}
o := add(o, l)
times := sub(times, 1)
if iszero(times) { break }
}
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function slice(bytes memory subject, uint256 start, uint256 end)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
let l := mload(subject) // Subject length.
if iszero(gt(l, end)) { end := l }
if iszero(gt(l, start)) { start := l }
if lt(start, end) {
result := mload(0x40)
let n := sub(end, start)
let i := add(subject, start)
let w := not(0x1f)
// Copy the `subject` one word at a time, backwards.
for { let j := and(add(n, 0x1f), w) } 1 {} {
mstore(add(result, j), mload(add(i, j)))
j := add(j, w) // `sub(j, 0x20)`.
if iszero(j) { break }
}
let o := add(add(result, 0x20), n)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, n) // Store the length.
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
/// `start` is a byte offset.
function slice(bytes memory subject, uint256 start)
internal
pure
returns (bytes memory result)
{
result = slice(subject, start, type(uint256).max);
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets. Faster than Solidity's native slicing.
function sliceCalldata(bytes calldata subject, uint256 start, uint256 end)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
end := xor(end, mul(xor(end, subject.length), lt(subject.length, end)))
start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
result.offset := add(subject.offset, start)
result.length := mul(lt(start, end), sub(end, start))
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
/// `start` is a byte offset. Faster than Solidity's native slicing.
function sliceCalldata(bytes calldata subject, uint256 start)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
result.offset := add(subject.offset, start)
result.length := mul(lt(start, subject.length), sub(subject.length, start))
}
}
/// @dev Reduces the size of `subject` to `n`.
/// If `n` is greater than the size of `subject`, this will be a no-op.
function truncate(bytes memory subject, uint256 n)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := subject
mstore(mul(lt(n, mload(result)), result), n)
}
}
/// @dev Returns a copy of `subject`, with the length reduced to `n`.
/// If `n` is greater than the size of `subject`, this will be a no-op.
function truncatedCalldata(bytes calldata subject, uint256 n)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
result.offset := subject.offset
result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n)))
}
}
/// @dev Returns all the indices of `needle` in `subject`.
/// The indices are byte offsets.
function indicesOf(bytes memory subject, bytes memory needle)
internal
pure
returns (uint256[] memory result)
{
/// @solidity memory-safe-assembly
assembly {
let searchLen := mload(needle)
if iszero(gt(searchLen, mload(subject))) {
result := mload(0x40)
let i := add(subject, 0x20)
let o := add(result, 0x20)
let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1)
let h := 0 // The hash of `needle`.
if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} {
let t := mload(i)
// Whether the first `searchLen % 32` bytes of `subject` and `needle` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, searchLen), h)) {
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(o, sub(i, add(subject, 0x20))) // Append to `result`.
o := add(o, 0x20)
i := add(i, searchLen) // Advance `i` by `searchLen`.
if searchLen {
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`.
// Allocate memory for result.
// We allocate one more word, so this array can be recycled for {split}.
mstore(0x40, add(o, 0x20))
}
}
}
/// @dev Returns an arrays of bytess based on the `delimiter` inside of the `subject` bytes.
function split(bytes memory subject, bytes memory delimiter)
internal
pure
returns (bytes[] 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))
for { let prevIndex := 0 } 1 {} {
let index := mload(indexPtr)
mstore(indexPtr, 0x60)
if iszero(eq(index, prevIndex)) {
let element := mload(0x40)
let l := sub(index, prevIndex)
mstore(element, l) // Store the length of the element.
// Copy the `subject` one word at a time, backwards.
for { let o := and(add(l, 0x1f), w) } 1 {} {
mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes.
// Allocate memory for the length and the bytes, rounded up to a multiple of 32.
mstore(0x40, add(element, and(add(l, 0x3f), w)))
mstore(indexPtr, element) // Store the `element` into the array.
}
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 bytes of `a` and `b`.
/// Cheaper than `bytes.concat()` and does not de-align the free memory pointer.
function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let w := not(0x1f)
let aLen := mload(a)
// Copy `a` one word at a time, backwards.
for { let o := and(add(aLen, 0x20), w) } 1 {} {
mstore(add(result, o), mload(add(a, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let bLen := mload(b)
let output := add(result, aLen)
// Copy `b` one word at a time, backwards.
for { let o := and(add(bLen, 0x20), w) } 1 {} {
mstore(add(output, o), mload(add(b, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let totalLen := add(aLen, bLen)
let last := add(add(result, 0x20), totalLen)
mstore(last, 0) // Zeroize the slot after the bytes.
mstore(result, totalLen) // Store the length.
mstore(0x40, add(last, 0x20)) // Allocate memory.
}
}
/// @dev Returns whether `a` equals `b`.
function eq(bytes memory a, bytes 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 bytes.
function eqs(bytes 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 Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`.
/// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1.
function cmp(bytes memory a, bytes memory b) internal pure returns (int256 result) {
/// @solidity memory-safe-assembly
assembly {
let aLen := mload(a)
let bLen := mload(b)
let n := and(xor(aLen, mul(xor(aLen, bLen), lt(bLen, aLen))), not(0x1f))
if n {
for { let i := 0x20 } 1 {} {
let x := mload(add(a, i))
let y := mload(add(b, i))
if iszero(or(xor(x, y), eq(i, n))) {
i := add(i, 0x20)
continue
}
result := sub(gt(x, y), lt(x, y))
break
}
}
// forgefmt: disable-next-item
if iszero(result) {
let l := 0x201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201
let x := and(mload(add(add(a, 0x20), n)), shl(shl(3, byte(sub(aLen, n), l)), not(0)))
let y := and(mload(add(add(b, 0x20), n)), shl(shl(3, byte(sub(bLen, n), l)), not(0)))
result := sub(gt(x, y), lt(x, y))
if iszero(result) { result := sub(gt(aLen, bLen), lt(aLen, bLen)) }
}
}
}
/// @dev Directly returns `a` without copying.
function directReturn(bytes memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
// Assumes that the bytes 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 bytes is produced
// by a method that doesn't zero right pad.
mstore(add(retStart, retUnpaddedSize), 0)
mstore(retStart, 0x20) // Store the return offset.
// End the transaction, returning the bytes.
return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
}
}
/// @dev Directly returns `a` with minimal copying.
function directReturn(bytes[] memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
let n := mload(a) // `a.length`.
let o := add(a, 0x20) // Start of elements in `a`.
let u := a // Highest memory slot.
let w := not(0x1f)
for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } {
let c := add(o, shl(5, i)) // Location of pointer to `a[i]`.
let s := mload(c) // `a[i]`.
let l := mload(s) // `a[i].length`.
let r := and(l, 0x1f) // `a[i].length % 32`.
let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`.
// If `s` comes before `o`, or `s` is not zero right padded.
if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) {
let m := mload(0x40)
mstore(m, l) // Copy `a[i].length`.
for {} 1 {} {
mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards.
z := add(z, w) // `sub(z, 0x20)`.
if iszero(z) { break }
}
let e := add(add(m, 0x20), l)
mstore(e, 0) // Zeroize the slot after the copied bytes.
mstore(0x40, add(e, 0x20)) // Allocate memory.
s := m
}
mstore(c, sub(s, o)) // Convert to calldata offset.
let t := add(l, add(s, 0x20))
if iszero(lt(t, u)) { u := t }
}
let retStart := add(a, w) // Assumes `a` doesn't start from scratch space.
mstore(retStart, 0x20) // Store the return offset.
return(retStart, add(0x40, sub(u, retStart))) // End the transaction.
}
}
/// @dev Returns the word at `offset`, without any bounds checks.
function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(add(add(a, 0x20), offset))
}
}
/// @dev Returns the word at `offset`, without any bounds checks.
function loadCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
result := calldataload(add(a.offset, offset))
}
}
/// @dev Returns a slice representing a static struct in the calldata. Performs bounds checks.
function staticStructInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
result.offset := add(a.offset, offset)
result.length := sub(a.length, offset)
if or(shr(64, or(l, a.offset)), gt(offset, l)) { revert(l, 0x00) }
}
}
/// @dev Returns a slice representing a dynamic struct in the calldata. Performs bounds checks.
function dynamicStructInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`.
result.offset := add(a.offset, s)
result.length := sub(a.length, s)
if or(shr(64, or(s, or(l, a.offset))), gt(offset, l)) { revert(l, 0x00) }
}
}
/// @dev Returns bytes in calldata. Performs bounds checks.
function bytesInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`.
result.offset := add(add(a.offset, s), 0x20)
result.length := calldataload(add(a.offset, s))
// forgefmt: disable-next-item
if or(shr(64, or(result.length, or(s, or(l, a.offset)))),
or(gt(add(s, result.length), l), gt(offset, l))) { revert(l, 0x00) }
}
}
/// @dev Returns empty calldata bytes. For silencing the compiler.
function emptyCalldata() internal pure returns (bytes calldata result) {
/// @solidity memory-safe-assembly
assembly {
result.length := 0
}
}
}
node_modules/solady/src/utils/LibString.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {LibBytes} from "./LibBytes.sol";
/// @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 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Goated string storage struct that totally MOGs, no cap, fr.
/// Uses less gas and bytecode than Solidity's native string storage. It's meta af.
/// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
struct StringStorage {
bytes32 _spacer;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* 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;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRING STORAGE OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sets the value of the string storage `$` to `s`.
function set(StringStorage storage $, string memory s) internal {
LibBytes.set(bytesStorage($), bytes(s));
}
/// @dev Sets the value of the string storage `$` to `s`.
function setCalldata(StringStorage storage $, string calldata s) internal {
LibBytes.setCalldata(bytesStorage($), bytes(s));
}
/// @dev Sets the value of the string storage `$` to the empty string.
function clear(StringStorage storage $) internal {
delete $._spacer;
}
/// @dev Returns whether the value stored is `$` is the empty string "".
function isEmpty(StringStorage storage $) internal view returns (bool) {
return uint256($._spacer) & 0xff == uint256(0);
}
/// @dev Returns the length of the value stored in `$`.
function length(StringStorage storage $) internal view returns (uint256) {
return LibBytes.length(bytesStorage($));
}
/// @dev Returns the value stored in `$`.
function get(StringStorage storage $) internal view returns (string memory) {
return string(LibBytes.get(bytesStorage($)));
}
/// @dev Returns the uint8 at index `i`. If out-of-bounds, returns 0.
function uint8At(StringStorage storage $, uint256 i) internal view returns (uint8) {
return LibBytes.uint8At(bytesStorage($), i);
}
/// @dev Helper to cast `$` to a `BytesStorage`.
function bytesStorage(StringStorage storage $)
internal
pure
returns (LibBytes.BytesStorage storage casted)
{
/// @solidity memory-safe-assembly
assembly {
casted.slot := $.slot
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the base 10 decimal representation of `value`.
function toString(uint256 value) internal pure returns (string memory result) {
/// @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.
result := add(mload(0x40), 0x80)
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end of the memory to calculate the length later.
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 {} {
result := add(result, w) // `sub(result, 1)`.
// Store the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(result, add(48, mod(temp, 10)))
temp := div(temp, 10) // Keep dividing `temp` until zero.
if iszero(temp) { break }
}
let n := sub(end, result)
result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the base 10 decimal representation of `value`.
function toString(int256 value) internal pure returns (string memory result) {
if (value >= 0) return toString(uint256(value));
unchecked {
result = 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 n := mload(result) // Load the string length.
mstore(result, 0x2d) // Store the '-' character.
result := sub(result, 1) // Move back the string pointer by a byte.
mstore(result, add(n, 1)) // Update the string length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HEXADECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `byteCount` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `byteCount * 2 + 2` bytes.
/// Reverts if `byteCount` is too small for the output to contain all the digits.
function toHexString(uint256 value, uint256 byteCount)
internal
pure
returns (string memory result)
{
result = toHexStringNoPrefix(value, byteCount);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `byteCount` bytes.
/// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte,
/// giving a total length of `byteCount * 2` bytes.
/// Reverts if `byteCount` is too small for the output to contain all the digits.
function toHexStringNoPrefix(uint256 value, uint256 byteCount)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, `byteCount * 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.
result := add(mload(0x40), and(add(shl(1, byteCount), 0x42), not(0x1f)))
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end to calculate the length later.
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let start := sub(result, add(byteCount, byteCount))
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 {} {
result := add(result, w) // `sub(result, 2)`.
mstore8(add(result, 1), mload(and(temp, 15)))
mstore8(result, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(xor(result, start)) { break }
}
if temp {
mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
revert(0x1c, 0x04)
}
let n := sub(end, result)
result := sub(result, 0x20)
mstore(result, n) // Store the length.
}
}
/// @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 result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store 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 result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
let n := add(mload(result), 2) // Compute the length.
mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero.
result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero.
mstore(result, sub(n, o)) // Store 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 result)
{
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
let n := mload(result) // Get the length.
result := add(result, o) // Move the pointer, accounting for leading zero.
mstore(result, sub(n, o)) // Store 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 result) {
/// @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.
result := add(mload(0x40), 0x80)
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end to calculate the length later.
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
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 {} {
result := add(result, w) // `sub(result, 2)`.
mstore8(add(result, 1), mload(and(temp, 15)))
mstore8(result, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(temp) { break }
}
let n := sub(end, result)
result := sub(result, 0x20)
mstore(result, n) // Store the length.
}
}
/// @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 result) {
result = toHexString(value);
/// @solidity memory-safe-assembly
assembly {
let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
let o := add(result, 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 result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store 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 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
// Allocate 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(result, 0x80))
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
result := add(result, 2)
mstore(result, 40) // Store the length.
let o := add(result, 0x20)
mstore(add(o, 40), 0) // Zeroize the slot after the string.
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 result) {
result = toHexStringNoPrefix(raw);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store 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 result) {
/// @solidity memory-safe-assembly
assembly {
let n := mload(raw)
result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
mstore(result, add(n, n)) // Store the length of the output.
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
let o := add(result, 0x20)
let end := add(raw, n)
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 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 {
result := 1
let mask := shl(7, div(not(0), 255))
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)
for { let end := add(o, mload(s)) } 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)
for { let end := add(o, mload(s)) } 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 `needle` replaced with `replacement`.
function replace(string memory subject, string memory needle, string memory replacement)
internal
pure
returns (string memory)
{
return string(LibBytes.replace(bytes(subject), bytes(needle), bytes(replacement)));
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(string memory subject, string memory needle, uint256 from)
internal
pure
returns (uint256)
{
return LibBytes.indexOf(bytes(subject), bytes(needle), from);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(string memory subject, string memory needle) internal pure returns (uint256) {
return LibBytes.indexOf(bytes(subject), bytes(needle), 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(string memory subject, string memory needle, uint256 from)
internal
pure
returns (uint256)
{
return LibBytes.lastIndexOf(bytes(subject), bytes(needle), from);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(string memory subject, string memory needle)
internal
pure
returns (uint256)
{
return LibBytes.lastIndexOf(bytes(subject), bytes(needle), type(uint256).max);
}
/// @dev Returns true if `needle` is found in `subject`, false otherwise.
function contains(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.contains(bytes(subject), bytes(needle));
}
/// @dev Returns whether `subject` starts with `needle`.
function startsWith(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.startsWith(bytes(subject), bytes(needle));
}
/// @dev Returns whether `subject` ends with `needle`.
function endsWith(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.endsWith(bytes(subject), bytes(needle));
}
/// @dev Returns `subject` repeated `times`.
function repeat(string memory subject, uint256 times) internal pure returns (string memory) {
return string(LibBytes.repeat(bytes(subject), times));
}
/// @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)
{
return string(LibBytes.slice(bytes(subject), start, end));
}
/// @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) {
return string(LibBytes.slice(bytes(subject), start, type(uint256).max));
}
/// @dev Returns all the indices of `needle` in `subject`.
/// The indices are byte offsets.
function indicesOf(string memory subject, string memory needle)
internal
pure
returns (uint256[] memory)
{
return LibBytes.indicesOf(bytes(subject), bytes(needle));
}
/// @dev Returns an 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)
{
bytes[] memory a = LibBytes.split(bytes(subject), bytes(delimiter));
/// @solidity memory-safe-assembly
assembly {
result := a
}
}
/// @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) {
return string(LibBytes.concat(bytes(a), bytes(b)));
}
/// @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 n := mload(subject)
if n {
result := mload(0x40)
let o := add(result, 0x20)
let d := sub(subject, result)
let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
for { let end := add(o, n) } 1 {} {
let b := byte(0, mload(add(d, o)))
mstore8(o, xor(and(shr(b, flags), 0x20), b))
o := add(o, 1)
if eq(o, end) { break }
}
mstore(result, n) // Store the length.
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate 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) // Store the length.
let o := add(result, 0x20)
mstore(o, s) // Store the bytes of the string.
mstore(add(o, n), 0) // Zeroize the slot after the string.
mstore(0x40, add(result, 0x40)) // Allocate memory.
}
}
/// @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 {
result := mload(0x40)
let end := add(s, mload(s))
let o := add(result, 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(o, c)
o := add(o, 1)
continue
}
let t := shr(248, mload(c))
mstore(o, mload(and(t, 0x1f)))
o := add(o, shr(5, t))
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(0x40, add(o, 0x20)) // Allocate 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 {
result := mload(0x40)
let o := add(result, 0x20)
if addDoubleQuotes {
mstore8(o, 34)
o := add(1, o)
}
// 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 { let end := add(s, mload(s)) } 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(o, c)
o := add(o, 1)
continue
}
mstore8(o, 0x5c) // "\\".
mstore8(add(o, 1), c)
o := add(o, 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(o, mload(0x19)) // "\\u00XX".
o := add(o, 6)
continue
}
mstore8(o, 0x5c) // "\\".
mstore8(add(o, 1), mload(add(c, 8)))
o := add(o, 2)
}
if addDoubleQuotes {
mstore8(o, 34)
o := add(1, o)
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(0x40, add(o, 0x20)) // Allocate 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 Encodes `s` so that it can be safely used in a URI,
/// just like `encodeURIComponent` in JavaScript.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
/// See: https://datatracker.ietf.org/doc/html/rfc2396
/// See: https://datatracker.ietf.org/doc/html/rfc3986
function encodeURIComponent(string memory s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
// Store "0123456789ABCDEF" in scratch space.
// Uppercased to be consistent with JavaScript's implementation.
mstore(0x0f, 0x30313233343536373839414243444546)
let o := add(result, 0x20)
for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
// If not in `[0-9A-Z-a-z-_.!~*'()]`.
if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) {
mstore8(o, 0x25) // '%'.
mstore8(add(o, 1), mload(and(shr(4, c), 15)))
mstore8(add(o, 2), mload(and(c, 15)))
o := add(o, 3)
continue
}
mstore8(o, c)
o := add(o, 1)
}
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/// @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 Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`.
/// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1.
function cmp(string memory a, string memory b) internal pure returns (int256) {
return LibBytes.cmp(bytes(a), bytes(b));
}
/// @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 {
result := mload(0x40) // Grab the free memory pointer.
mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes).
mstore(result, 0) // Zeroize the length slot.
mstore(add(result, 0x1f), packed) // Store the length and bytes.
mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes.
}
}
/// @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 aLen := mload(a)
// We don't need to zero right pad the strings,
// since this is our own custom non-standard packing scheme.
result :=
mul(
or( // Load the length and the bytes of `a` and `b`.
shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))),
// `totalLen != 0 && totalLen < 31`. Abuses underflow.
// Assumes that the lengths are valid and within the block gas limit.
lt(sub(add(aLen, 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 {
resultA := mload(0x40) // Grab the free memory pointer.
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 {
/// @solidity memory-safe-assembly
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)
mstore(retStart, 0x20) // Store the return offset.
// End the transaction, returning the string.
return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
}
}
}
contracts/layer1/automata-attestation/AutomataDcapV3Attestation_Layout.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title AutomataDcapV3AttestationLayout
/// @notice Storage layout documentation for AutomataDcapV3Attestation
/// @dev This file is auto-generated by gen-layouts.sh. DO NOT EDIT MANUALLY.
/// @custom:security-contact security@taiko.xyz
// solhint-disable max-line-length
// _initialized | uint8 | Slot: 0 | Offset: 0 | Bytes: 1
// _initializing | bool | Slot: 0 | Offset: 1 | Bytes: 1
// __gap | uint256[50] | Slot: 1 | Offset: 0 | Bytes: 1600
// _owner | address | Slot: 51 | Offset: 0 | Bytes: 20
// __gap | uint256[49] | Slot: 52 | Offset: 0 | Bytes: 1568
// _pendingOwner | address | Slot: 101 | Offset: 0 | Bytes: 20
// __gap | uint256[49] | Slot: 102 | Offset: 0 | Bytes: 1568
// __gapFromOldAddressResolver | uint256[50] | Slot: 151 | Offset: 0 | Bytes: 1600
// __reentry | uint8 | Slot: 201 | Offset: 0 | Bytes: 1
// __paused | uint8 | Slot: 201 | Offset: 1 | Bytes: 1
// __gap | uint256[49] | Slot: 202 | Offset: 0 | Bytes: 1568
// sigVerifyLib | contract ISigVerifyLib | Slot: 251 | Offset: 0 | Bytes: 20
// pemCertLib | contract IPEMCertChainLib | Slot: 252 | Offset: 0 | Bytes: 20
// checkLocalEnclaveReport | bool | Slot: 252 | Offset: 20 | Bytes: 1
// trustedUserMrEnclave | mapping(bytes32 => bool) | Slot: 253 | Offset: 0 | Bytes: 32
// trustedUserMrSigner | mapping(bytes32 => bool) | Slot: 254 | Offset: 0 | Bytes: 32
// serialNumIsRevoked | mapping(uint256 => mapping(bytes => bool)) | Slot: 255 | Offset: 0 | Bytes: 32
// tcbInfo | mapping(string => struct TCBInfoStruct.TCBInfo) | Slot: 256 | Offset: 0 | Bytes: 32
// qeIdentity | struct EnclaveIdStruct.EnclaveId | Slot: 257 | Offset: 0 | Bytes: 128
// __gap | uint256[39] | Slot: 261 | Offset: 0 | Bytes: 1248
contracts/layer1/automata-attestation/interfaces/IAttestation.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "../lib/QuoteV3Auth/V3Struct.sol";
/// @title IAttestation
/// @custom:security-contact security@taiko.xyz
interface IAttestation {
function verifyAttestation(bytes calldata data) external returns (bool);
function verifyParsedQuote(V3Struct.ParsedV3QuoteStruct calldata v3quote)
external
returns (bool success, bytes memory retData);
}
contracts/layer1/automata-attestation/interfaces/ISigVerifyLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title ISigVerifyLib
/// @custom:security-contact security@taiko.xyz
interface ISigVerifyLib {
function verifyES256Signature(
bytes memory tbs,
bytes memory signature,
bytes memory publicKey
)
external
view
returns (bool sigValid);
}
contracts/layer1/automata-attestation/lib/EnclaveIdStruct.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title EnclaveIdStruct
/// @custom:security-contact security@taiko.xyz
library EnclaveIdStruct {
struct EnclaveId {
bytes4 miscselect; // Slot 1:
bytes4 miscselectMask;
uint16 isvprodid;
bytes16 attributes; // Slot 2
bytes16 attributesMask;
bytes32 mrsigner; // Slot 3
TcbLevel[] tcbLevels; // Slot 4
}
struct TcbLevel {
TcbObj tcb;
EnclaveIdStatus tcbStatus;
}
struct TcbObj {
uint16 isvsvn;
}
enum EnclaveIdStatus {
OK,
SGX_ENCLAVE_REPORT_ISVSVN_REVOKED
}
}
contracts/layer1/automata-attestation/lib/PEMCertChainLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "../utils/Asn1Decode.sol";
import "../utils/BytesUtils.sol";
import "../utils/X509DateUtils.sol";
import "./interfaces/IPEMCertChainLib.sol";
import "solady/src/utils/LibString.sol";
/// @title PEMCertChainLib
/// @custom:security-contact security@taiko.xyz
contract PEMCertChainLib is IPEMCertChainLib {
using Asn1Decode for bytes;
using NodePtr for uint256;
using BytesUtils for bytes;
string internal constant HEADER = "-----BEGIN CERTIFICATE-----";
string internal constant FOOTER = "-----END CERTIFICATE-----";
uint256 internal constant HEADER_LENGTH = 27;
uint256 internal constant FOOTER_LENGTH = 25;
string internal constant PCK_COMMON_NAME = "Intel SGX PCK Certificate";
string internal constant PLATFORM_ISSUER_NAME = "Intel SGX PCK Platform CA";
string internal constant PROCESSOR_ISSUER_NAME = "Intel SGX PCK Processor CA";
bytes internal constant SGX_EXTENSION_OID = hex"2A864886F84D010D01";
bytes internal constant TCB_OID = hex"2A864886F84D010D0102";
bytes internal constant PCESVN_OID = hex"2A864886F84D010D010211";
bytes internal constant PCEID_OID = hex"2A864886F84D010D0103";
bytes internal constant FMSPC_OID = hex"2A864886F84D010D0104";
// https://github.com/intel/SGXDataCenterAttestationPrimitives/blob/e7604e02331b3377f3766ed3653250e03af72d45/QuoteVerification/QVL/Src/AttestationLibrary/src/CertVerification/X509Constants.h#L64
uint256 constant SGX_TCB_CPUSVN_SIZE = 16;
struct PCKTCBFlags {
bool fmspcFound;
bool pceidFound;
bool tcbFound;
}
function splitCertificateChain(
bytes memory pemChain,
uint256 size
)
external
pure
returns (bool success, bytes[] memory certs)
{
certs = new bytes[](size);
string memory pemChainStr = string(pemChain);
uint256 index = 0;
uint256 len = pemChain.length;
for (uint256 i; i < size; ++i) {
string memory input;
if (i != 0) {
input = LibString.slice(pemChainStr, index, index + len);
} else {
input = pemChainStr;
}
uint256 increment;
(success, certs[i], increment) = _removeHeadersAndFooters(input);
if (!success) {
return (false, certs);
}
index += increment;
}
success = true;
}
function decodeCert(
bytes memory der,
bool isPckCert
)
external
pure
returns (bool success, ECSha256Certificate memory cert)
{
uint256 root = der.root();
// Entering tbsCertificate sequence
uint256 tbsParentPtr = der.firstChildOf(root);
// Begin iterating through the descendants of tbsCertificate
uint256 tbsPtr = der.firstChildOf(tbsParentPtr);
// The Serial Number is located one element below Version
// The issuer commonName value is contained in the Issuer sequence
// which is 3 elements below the first element of the tbsCertificate sequence
// The Validity sequence is located 4 elements below the first element of the tbsCertificate
// sequence
// The subject commonName value is contained in the Subject sequence
// which is 5 elements below the first element of the tbsCertificate sequence
// The PublicKey is located in the second element of subjectPublicKeyInfo sequence
// which is 6 elements below the first element of the tbsCertificate sequence
tbsPtr = der.nextSiblingOf(tbsPtr);
{
bytes memory serialNumBytes = der.bytesAt(tbsPtr);
cert.serialNumber = serialNumBytes;
}
tbsPtr = der.nextSiblingOf(tbsPtr);
tbsPtr = der.nextSiblingOf(tbsPtr);
if (isPckCert) {
uint256 issuerPtr = der.firstChildOf(tbsPtr);
issuerPtr = der.firstChildOf(issuerPtr);
issuerPtr = der.firstChildOf(issuerPtr);
issuerPtr = der.nextSiblingOf(issuerPtr);
cert.pck.issuerName = string(der.bytesAt(issuerPtr));
bool issuerNameIsValid = LibString.eq(cert.pck.issuerName, PLATFORM_ISSUER_NAME)
|| LibString.eq(cert.pck.issuerName, PROCESSOR_ISSUER_NAME);
if (!issuerNameIsValid) {
return (false, cert);
}
}
tbsPtr = der.nextSiblingOf(tbsPtr);
{
uint256 notBeforePtr = der.firstChildOf(tbsPtr);
uint256 notAfterPtr = der.nextSiblingOf(notBeforePtr);
bytes1 notBeforeTag = der[notBeforePtr.ixs()];
bytes1 notAfterTag = der[notAfterPtr.ixs()];
if (
(notBeforeTag != 0x17 && notBeforeTag != 0x18)
|| (notAfterTag != 0x17 && notAfterTag != 0x18)
) {
return (false, cert);
}
cert.notBefore = X509DateUtils.toTimestamp(der.bytesAt(notBeforePtr));
cert.notAfter = X509DateUtils.toTimestamp(der.bytesAt(notAfterPtr));
}
tbsPtr = der.nextSiblingOf(tbsPtr);
if (isPckCert) {
uint256 subjectPtr = der.firstChildOf(tbsPtr);
subjectPtr = der.firstChildOf(subjectPtr);
subjectPtr = der.firstChildOf(subjectPtr);
subjectPtr = der.nextSiblingOf(subjectPtr);
cert.pck.commonName = string(der.bytesAt(subjectPtr));
if (!LibString.eq(cert.pck.commonName, PCK_COMMON_NAME)) {
return (false, cert);
}
}
tbsPtr = der.nextSiblingOf(tbsPtr);
{
// Entering subjectPublicKeyInfo sequence
uint256 subjectPublicKeyInfoPtr = der.firstChildOf(tbsPtr);
subjectPublicKeyInfoPtr = der.nextSiblingOf(subjectPublicKeyInfoPtr);
// The Signature sequence is located two sibling elements below the tbsCertificate
// element
uint256 sigPtr = der.nextSiblingOf(tbsParentPtr);
sigPtr = der.nextSiblingOf(sigPtr);
// Skip three bytes to the right
// the three bytes in question: 0x034700 or 0x034800 or 0x034900
sigPtr = NodePtr.getPtr(sigPtr.ixs() + 3, sigPtr.ixf() + 3, sigPtr.ixl());
sigPtr = der.firstChildOf(sigPtr);
bytes memory sigX = _trimBytes(der.bytesAt(sigPtr), 32);
sigPtr = der.nextSiblingOf(sigPtr);
bytes memory sigY = _trimBytes(der.bytesAt(sigPtr), 32);
cert.tbsCertificate = der.allBytesAt(tbsParentPtr);
cert.pubKey = _trimBytes(der.bytesAt(subjectPublicKeyInfoPtr), 64);
cert.signature = abi.encodePacked(sigX, sigY);
}
if (isPckCert) {
// entering Extension sequence
tbsPtr = der.nextSiblingOf(tbsPtr);
// check for the extension tag
if (der[tbsPtr.ixs()] != 0xA3) {
return (false, cert);
}
tbsPtr = der.firstChildOf(tbsPtr);
tbsPtr = der.firstChildOf(tbsPtr);
bool sgxExtnTraversedSuccessfully;
uint256 pcesvn;
uint256[] memory cpuSvns;
bytes memory fmspcBytes;
bytes memory pceidBytes;
(sgxExtnTraversedSuccessfully, pcesvn, cpuSvns, fmspcBytes, pceidBytes) =
_findPckTcbInfo(der, tbsPtr, tbsParentPtr);
if (!sgxExtnTraversedSuccessfully) {
return (false, cert);
}
cert.pck.sgxExtension.pcesvn = pcesvn;
cert.pck.sgxExtension.sgxTcbCompSvnArr = cpuSvns;
cert.pck.sgxExtension.pceid = LibString.toHexStringNoPrefix(pceidBytes);
cert.pck.sgxExtension.fmspc = LibString.toHexStringNoPrefix(fmspcBytes);
cert.isPck = true;
}
success = true;
}
function _removeHeadersAndFooters(string memory pemData)
private
pure
returns (bool success, bytes memory extracted, uint256 endIndex)
{
// Check if the input contains the "BEGIN" and "END" headers
uint256 beginPos = LibString.indexOf(pemData, HEADER);
uint256 endPos = LibString.indexOf(pemData, FOOTER);
bool headerFound = beginPos != LibString.NOT_FOUND;
bool footerFound = endPos != LibString.NOT_FOUND;
if (!headerFound || !footerFound) {
return (false, extracted, endIndex);
}
// Extract the content between the headers
uint256 contentStart = beginPos + HEADER_LENGTH;
// Extract and return the content
bytes memory contentBytes;
// do not include newline
bytes memory delimiter = hex"0a";
string memory contentSlice = LibString.slice(pemData, contentStart, endPos);
string[] memory split = LibString.split(contentSlice, string(delimiter));
string memory contentStr;
uint256 size = split.length;
for (uint256 i; i < size; ++i) {
contentStr = LibString.concat(contentStr, split[i]);
}
contentBytes = bytes(contentStr);
return (true, contentBytes, endPos + FOOTER_LENGTH);
}
function _trimBytes(
bytes memory input,
uint256 expectedLength
)
private
pure
returns (bytes memory output)
{
uint256 n = input.length;
if (n <= expectedLength) {
return input;
}
uint256 lengthDiff = n - expectedLength;
output = input.substring(lengthDiff, expectedLength);
}
function _findPckTcbInfo(
bytes memory der,
uint256 tbsPtr,
uint256 tbsParentPtr
)
private
pure
returns (
bool success,
uint256 pcesvn,
uint256[] memory cpusvns,
bytes memory fmspcBytes,
bytes memory pceidBytes
)
{
// iterate through the elements in the Extension sequence
// until we locate the SGX Extension OID
while (tbsPtr != 0) {
uint256 internalPtr = der.firstChildOf(tbsPtr);
if (der[internalPtr.ixs()] != 0x06) {
return (false, pcesvn, cpusvns, fmspcBytes, pceidBytes);
}
if (BytesUtils.compareBytes(der.bytesAt(internalPtr), SGX_EXTENSION_OID)) {
// 1.2.840.113741.1.13.1
internalPtr = der.nextSiblingOf(internalPtr);
uint256 extnValueParentPtr = der.rootOfOctetStringAt(internalPtr);
uint256 extnValuePtr = der.firstChildOf(extnValueParentPtr);
// Copy flags to memory to avoid stack too deep
PCKTCBFlags memory flags;
while (!(flags.fmspcFound && flags.pceidFound && flags.tcbFound)) {
uint256 extnValueOidPtr = der.firstChildOf(extnValuePtr);
if (der[extnValueOidPtr.ixs()] != 0x06) {
return (false, pcesvn, cpusvns, fmspcBytes, pceidBytes);
}
if (BytesUtils.compareBytes(der.bytesAt(extnValueOidPtr), TCB_OID)) {
// 1.2.840.113741.1.13.1.2
(flags.tcbFound, pcesvn, cpusvns) = _findTcb(der, extnValueOidPtr);
}
if (BytesUtils.compareBytes(der.bytesAt(extnValueOidPtr), PCEID_OID)) {
// 1.2.840.113741.1.13.1.3
uint256 pceidPtr = der.nextSiblingOf(extnValueOidPtr);
pceidBytes = der.bytesAt(pceidPtr);
flags.pceidFound = true;
}
if (BytesUtils.compareBytes(der.bytesAt(extnValueOidPtr), FMSPC_OID)) {
// 1.2.840.113741.1.13.1.4
uint256 fmspcPtr = der.nextSiblingOf(extnValueOidPtr);
fmspcBytes = der.bytesAt(fmspcPtr);
flags.fmspcFound = true;
}
if (extnValuePtr.ixl() < extnValueParentPtr.ixl()) {
extnValuePtr = der.nextSiblingOf(extnValuePtr);
} else {
break;
}
}
success = flags.fmspcFound && flags.pceidFound && flags.tcbFound;
break;
}
if (tbsPtr.ixl() < tbsParentPtr.ixl()) {
tbsPtr = der.nextSiblingOf(tbsPtr);
} else {
tbsPtr = 0; // exit
}
}
}
function _findTcb(
bytes memory der,
uint256 oidPtr
)
private
pure
returns (bool success, uint256 pcesvn, uint256[] memory cpusvns)
{
// sibling of tcbOid
uint256 tcbPtr = der.nextSiblingOf(oidPtr);
// get the first svn object in the sequence
uint256 svnParentPtr = der.firstChildOf(tcbPtr);
cpusvns = new uint256[](SGX_TCB_CPUSVN_SIZE);
for (uint256 i; i < SGX_TCB_CPUSVN_SIZE + 1; ++i) {
uint256 svnPtr = der.firstChildOf(svnParentPtr); // OID
uint256 svnValuePtr = der.nextSiblingOf(svnPtr); // value
bytes memory svnValueBytes = der.bytesAt(svnValuePtr);
uint16 svnValue = svnValueBytes.length < 2
? uint16(bytes2(svnValueBytes)) / 256
: uint16(bytes2(svnValueBytes));
if (BytesUtils.compareBytes(der.bytesAt(svnPtr), PCESVN_OID)) {
// pcesvn is 4 bytes in size
pcesvn = uint256(svnValue);
} else {
// each cpusvn is at maximum two bytes in size
uint256 cpusvn = uint256(svnValue);
cpusvns[i] = cpusvn;
}
// iterate to the next svn object in the sequence
svnParentPtr = der.nextSiblingOf(svnParentPtr);
}
success = true;
}
}
contracts/layer1/automata-attestation/lib/QuoteV3Auth/V3Parser.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "../../lib/PEMCertChainLib.sol";
import "../../utils/BytesUtils.sol";
import "./V3Struct.sol";
import "solady/src/utils/Base64.sol";
/// @title V3Parser
/// @custom:security-contact security@taiko.xyz
library V3Parser {
using BytesUtils for bytes;
uint256 internal constant MINIMUM_QUOTE_LENGTH = 1020;
bytes2 internal constant SUPPORTED_QUOTE_VERSION = 0x0300;
bytes2 internal constant SUPPORTED_ATTESTATION_KEY_TYPE = 0x0200;
// SGX only
bytes4 internal constant SUPPORTED_TEE_TYPE = 0;
bytes16 internal constant VALID_QE_VENDOR_ID = 0x939a7233f79c4ca9940a0db3957f0607;
error V3PARSER_INVALID_QUOTE_LENGTN();
error V3PARSER_INVALID_QUOTE_MEMBER_LENGTN();
error V3PARSER_INVALID_QEREPORT_LENGTN();
error V3PARSER_UNSUPPORT_CERTIFICATION_TYPE();
error V3PARSER_INVALID_CERTIFICATION_CHAIN_SIZE();
error V3PARSER_INVALID_CERTIFICATION_CHAIN_DATA();
error V3PARSER_INVALID_ECDSA_SIGNATURE();
error V3PARSER_INVALID_QEAUTHDATA_SIZE();
function parseInput(
bytes memory quote,
address pemCertLibAddr
)
internal
pure
returns (bool success, V3Struct.ParsedV3QuoteStruct memory v3ParsedQuote)
{
if (quote.length <= MINIMUM_QUOTE_LENGTH) {
return (false, v3ParsedQuote);
}
uint256 localAuthDataSize = littleEndianDecode(quote.substring(432, 4));
if (quote.length - 436 != localAuthDataSize) {
return (false, v3ParsedQuote);
}
bytes memory rawHeader = quote.substring(0, 48);
(bool headerVerifiedSuccessfully, V3Struct.Header memory header) =
parseAndVerifyHeader(rawHeader);
if (!headerVerifiedSuccessfully) {
return (false, v3ParsedQuote);
}
(bool authDataVerifiedSuccessfully, V3Struct.ECDSAQuoteV3AuthData memory authDataV3) =
parseAuthDataAndVerifyCertType(quote.substring(436, localAuthDataSize), pemCertLibAddr);
if (!authDataVerifiedSuccessfully) {
return (false, v3ParsedQuote);
}
bytes memory rawLocalEnclaveReport = quote.substring(48, 384);
V3Struct.EnclaveReport memory localEnclaveReport = parseEnclaveReport(rawLocalEnclaveReport);
v3ParsedQuote = V3Struct.ParsedV3QuoteStruct({
header: header, localEnclaveReport: localEnclaveReport, v3AuthData: authDataV3
});
success = true;
}
function validateParsedInput(V3Struct.ParsedV3QuoteStruct memory v3Quote)
internal
pure
returns (
bool success,
V3Struct.Header memory header,
V3Struct.EnclaveReport memory localEnclaveReport,
bytes memory signedQuoteData, // concatenation of header and local enclave report bytes
V3Struct.ECDSAQuoteV3AuthData memory authDataV3
)
{
success = true;
localEnclaveReport = v3Quote.localEnclaveReport;
V3Struct.EnclaveReport memory pckSignedQeReport = v3Quote.v3AuthData.pckSignedQeReport;
if (
localEnclaveReport.reserved3.length != 96 || localEnclaveReport.reserved4.length != 60
|| localEnclaveReport.reportData.length != 64
) revert V3PARSER_INVALID_QUOTE_MEMBER_LENGTN();
if (
pckSignedQeReport.reserved3.length != 96 || pckSignedQeReport.reserved4.length != 60
|| pckSignedQeReport.reportData.length != 64
) {
revert V3PARSER_INVALID_QEREPORT_LENGTN();
}
if (v3Quote.v3AuthData.certification.certType != 5) {
revert V3PARSER_UNSUPPORT_CERTIFICATION_TYPE();
}
if (v3Quote.v3AuthData.certification.decodedCertDataArray.length != 3) {
revert V3PARSER_INVALID_CERTIFICATION_CHAIN_SIZE();
}
if (
v3Quote.v3AuthData.ecdsa256BitSignature.length != 64
|| v3Quote.v3AuthData.ecdsaAttestationKey.length != 64
|| v3Quote.v3AuthData.qeReportSignature.length != 64
) {
revert V3PARSER_INVALID_ECDSA_SIGNATURE();
}
if (
v3Quote.v3AuthData.qeAuthData.parsedDataSize
!= v3Quote.v3AuthData.qeAuthData.data.length
) {
revert V3PARSER_INVALID_QEAUTHDATA_SIZE();
}
uint32 totalQuoteSize = 48 // header
+ 384 // local QE report
+ 64 // ecdsa256BitSignature
+ 64 // ecdsaAttestationKey
+ 384 // QE report
+ 64 // qeReportSignature
+ 2 // sizeof(v3Quote.v3AuthData.qeAuthData.parsedDataSize)
+ v3Quote.v3AuthData.qeAuthData.parsedDataSize + 2 // sizeof(v3Quote.v3AuthData.certification.certType)
+ 4 // sizeof(v3Quote.v3AuthData.certification.certDataSize)
+ v3Quote.v3AuthData.certification.certDataSize;
if (totalQuoteSize <= MINIMUM_QUOTE_LENGTH) {
revert V3PARSER_INVALID_QUOTE_LENGTN();
}
header = v3Quote.header;
bytes memory headerBytes = abi.encodePacked(
header.version,
header.attestationKeyType,
header.teeType,
header.qeSvn,
header.pceSvn,
header.qeVendorId,
header.userData
);
signedQuoteData = abi.encodePacked(headerBytes, V3Parser.packQEReport(localEnclaveReport));
authDataV3 = v3Quote.v3AuthData;
}
function parseEnclaveReport(bytes memory rawEnclaveReport)
internal
pure
returns (V3Struct.EnclaveReport memory enclaveReport)
{
enclaveReport.cpuSvn = bytes16(rawEnclaveReport.substring(0, 16));
enclaveReport.miscSelect = bytes4(rawEnclaveReport.substring(16, 4));
enclaveReport.reserved1 = bytes28(rawEnclaveReport.substring(20, 28));
enclaveReport.attributes = bytes16(rawEnclaveReport.substring(48, 16));
enclaveReport.mrEnclave = bytes32(rawEnclaveReport.substring(64, 32));
enclaveReport.reserved2 = bytes32(rawEnclaveReport.substring(96, 32));
enclaveReport.mrSigner = bytes32(rawEnclaveReport.substring(128, 32));
enclaveReport.reserved3 = rawEnclaveReport.substring(160, 96);
enclaveReport.isvProdId = uint16(littleEndianDecode(rawEnclaveReport.substring(256, 2)));
enclaveReport.isvSvn = uint16(littleEndianDecode(rawEnclaveReport.substring(258, 2)));
enclaveReport.reserved4 = rawEnclaveReport.substring(260, 60);
enclaveReport.reportData = rawEnclaveReport.substring(320, 64);
}
function littleEndianDecode(bytes memory encoded) private pure returns (uint256 decoded) {
uint256 size = encoded.length;
for (uint256 i; i < size; ++i) {
uint256 digits = uint256(uint8(bytes1(encoded[i])));
uint256 upperDigit = digits / 16;
uint256 lowerDigit = digits % 16;
uint256 acc = lowerDigit * (16 ** (2 * i));
acc += upperDigit * (16 ** ((2 * i) + 1));
decoded += acc;
}
}
function parseAndVerifyHeader(bytes memory rawHeader)
private
pure
returns (bool success, V3Struct.Header memory header)
{
bytes2 version = bytes2(rawHeader.substring(0, 2));
if (version != SUPPORTED_QUOTE_VERSION) {
return (false, header);
}
bytes2 attestationKeyType = bytes2(rawHeader.substring(2, 2));
if (attestationKeyType != SUPPORTED_ATTESTATION_KEY_TYPE) {
return (false, header);
}
bytes4 teeType = bytes4(rawHeader.substring(4, 4));
if (teeType != SUPPORTED_TEE_TYPE) {
return (false, header);
}
bytes16 qeVendorId = bytes16(rawHeader.substring(12, 16));
if (qeVendorId != VALID_QE_VENDOR_ID) {
return (false, header);
}
header = V3Struct.Header({
version: version,
attestationKeyType: attestationKeyType,
teeType: teeType,
qeSvn: bytes2(rawHeader.substring(8, 2)),
pceSvn: bytes2(rawHeader.substring(10, 2)),
qeVendorId: qeVendorId,
userData: bytes20(rawHeader.substring(28, 20))
});
success = true;
}
function parseAuthDataAndVerifyCertType(
bytes memory rawAuthData,
address pemCertLibAddr
)
private
pure
returns (bool success, V3Struct.ECDSAQuoteV3AuthData memory authDataV3)
{
V3Struct.QEAuthData memory qeAuthData;
qeAuthData.parsedDataSize = uint16(littleEndianDecode(rawAuthData.substring(576, 2)));
qeAuthData.data = rawAuthData.substring(578, qeAuthData.parsedDataSize);
uint256 offset = 578 + qeAuthData.parsedDataSize;
V3Struct.CertificationData memory cert;
cert.certType = uint16(littleEndianDecode(rawAuthData.substring(offset, 2)));
if (cert.certType < 1 || cert.certType > 5) {
return (false, authDataV3);
}
offset += 2;
cert.certDataSize = uint32(littleEndianDecode(rawAuthData.substring(offset, 4)));
offset += 4;
bytes memory certData = rawAuthData.substring(offset, cert.certDataSize);
cert.decodedCertDataArray = parseCerificationChainBytes(certData, pemCertLibAddr);
authDataV3.ecdsa256BitSignature = rawAuthData.substring(0, 64);
authDataV3.ecdsaAttestationKey = rawAuthData.substring(64, 64);
bytes memory rawQeReport = rawAuthData.substring(128, 384);
authDataV3.pckSignedQeReport = parseEnclaveReport(rawQeReport);
authDataV3.qeReportSignature = rawAuthData.substring(512, 64);
authDataV3.qeAuthData = qeAuthData;
authDataV3.certification = cert;
success = true;
}
/// enclaveReport to bytes for hash calculation.
/// the only difference between enclaveReport and packedQEReport is the
/// order of isvProdId and isvSvn. enclaveReport is in little endian, while
/// in bytes should be in big endian according to Intel spec.
/// @param enclaveReport enclave report
/// @return packedQEReport enclave report in bytes
function packQEReport(V3Struct.EnclaveReport memory enclaveReport)
internal
pure
returns (bytes memory packedQEReport)
{
uint16 isvProdIdPackBE = (enclaveReport.isvProdId >> 8) | (enclaveReport.isvProdId << 8);
uint16 isvSvnPackBE = (enclaveReport.isvSvn >> 8) | (enclaveReport.isvSvn << 8);
packedQEReport = abi.encodePacked(
enclaveReport.cpuSvn,
enclaveReport.miscSelect,
enclaveReport.reserved1,
enclaveReport.attributes,
enclaveReport.mrEnclave,
enclaveReport.reserved2,
enclaveReport.mrSigner,
enclaveReport.reserved3,
isvProdIdPackBE,
isvSvnPackBE,
enclaveReport.reserved4,
enclaveReport.reportData
);
}
function parseCerificationChainBytes(
bytes memory certBytes,
address pemCertLibAddr
)
internal
pure
returns (bytes[3] memory certChainData)
{
IPEMCertChainLib pemCertLib = PEMCertChainLib(pemCertLibAddr);
IPEMCertChainLib.ECSha256Certificate[] memory parsedQuoteCerts;
(bool certParsedSuccessfully, bytes[] memory quoteCerts) =
pemCertLib.splitCertificateChain(certBytes, 3);
if (!certParsedSuccessfully) {
revert V3PARSER_INVALID_CERTIFICATION_CHAIN_DATA();
}
parsedQuoteCerts = new IPEMCertChainLib.ECSha256Certificate[](3);
for (uint256 i; i < 3; ++i) {
quoteCerts[i] = Base64.decode(string(quoteCerts[i]));
}
certChainData = [quoteCerts[0], quoteCerts[1], quoteCerts[2]];
}
}
contracts/layer1/automata-attestation/lib/QuoteV3Auth/V3Struct.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title V3Struct
/// @custom:security-contact security@taiko.xyz
library V3Struct {
struct Header {
bytes2 version;
bytes2 attestationKeyType;
bytes4 teeType;
bytes2 qeSvn;
bytes2 pceSvn;
bytes16 qeVendorId;
bytes20 userData;
}
struct EnclaveReport {
bytes16 cpuSvn;
bytes4 miscSelect;
bytes28 reserved1;
bytes16 attributes;
bytes32 mrEnclave;
bytes32 reserved2;
bytes32 mrSigner;
bytes reserved3; // 96 bytes
uint16 isvProdId;
uint16 isvSvn;
bytes reserved4; // 60 bytes
bytes reportData; // 64 bytes - For QEReports, this contains the hash of the concatenation
// of attestation key and QEAuthData
}
struct QEAuthData {
uint16 parsedDataSize;
bytes data;
}
struct CertificationData {
uint16 certType;
// TODO(Yue): In encoded path, we need to calculate the size of certDataArray
// certDataSize = len(join((BEGIN_CERT, certArray[i], END_CERT) for i in 0..3))
// But for plain bytes path, we don't need that.
uint32 certDataSize;
bytes[3] decodedCertDataArray; // base64 decoded cert bytes array
}
struct ECDSAQuoteV3AuthData {
bytes ecdsa256BitSignature; // 64 bytes
bytes ecdsaAttestationKey; // 64 bytes
EnclaveReport pckSignedQeReport; // 384 bytes
bytes qeReportSignature; // 64 bytes
QEAuthData qeAuthData;
CertificationData certification;
}
struct ParsedV3QuoteStruct {
Header header;
EnclaveReport localEnclaveReport;
ECDSAQuoteV3AuthData v3AuthData;
}
}
contracts/layer1/automata-attestation/lib/TCBInfoStruct.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title TCBInfoStruct
/// @custom:security-contact security@taiko.xyz
library TCBInfoStruct {
struct TCBInfo {
string pceid;
string fmspc;
TCBLevelObj[] tcbLevels;
}
struct TCBLevelObj {
uint256 pcesvn;
uint8[] sgxTcbCompSvnArr;
TCBStatus status;
}
enum TCBStatus {
OK,
TCB_SW_HARDENING_NEEDED,
TCB_CONFIGURATION_AND_SW_HARDENING_NEEDED,
TCB_CONFIGURATION_NEEDED,
TCB_OUT_OF_DATE,
TCB_OUT_OF_DATE_CONFIGURATION_NEEDED,
TCB_REVOKED,
TCB_UNRECOGNIZED
}
}
contracts/layer1/automata-attestation/lib/interfaces/IPEMCertChainLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title IPEMCertChainLib
/// @custom:security-contact security@taiko.xyz
interface IPEMCertChainLib {
struct ECSha256Certificate {
uint256 notBefore;
uint256 notAfter;
bytes serialNumber;
bytes tbsCertificate;
bytes pubKey;
bytes signature;
bool isPck;
PCKCertificateField pck;
}
struct PCKCertificateField {
string commonName;
string issuerName;
PCKTCBInfo sgxExtension;
}
struct PCKTCBInfo {
string pceid;
string fmspc;
uint256 pcesvn;
uint256[] sgxTcbCompSvnArr;
}
enum CRL {
PCK,
ROOT
}
function splitCertificateChain(
bytes memory pemChain,
uint256 size
)
external
pure
returns (bool success, bytes[] memory certs);
function decodeCert(
bytes memory der,
bool isPckCert
)
external
pure
returns (bool success, ECSha256Certificate memory cert);
}
contracts/layer1/automata-attestation/utils/Asn1Decode.sol
// SPDX-License-Identifier: MIT
// Original source: https://github.com/JonahGroendal/asn1-decode
pragma solidity ^0.8.24;
// Inspired by PufferFinance/rave - Apache-2.0 license
// https://github.com/JonahGroendal/asn1-decode/blob/5c2d1469fc678513753786acb441e597969192ec/contracts/Asn1Decode.sol
import "./BytesUtils.sol";
/// @title NodePtr
/// @custom:security-contact security@taiko.xyz
library NodePtr {
// Unpack first byte index
function ixs(uint256 self) internal pure returns (uint256) {
return uint80(self);
}
// Unpack first content byte index
function ixf(uint256 self) internal pure returns (uint256) {
return uint80(self >> 80);
}
// Unpack last content byte index
function ixl(uint256 self) internal pure returns (uint256) {
return uint80(self >> 160);
}
// Pack 3 uint80s into a uint256
function getPtr(uint256 _ixs, uint256 _ixf, uint256 _ixl) internal pure returns (uint256) {
_ixs |= _ixf << 80;
_ixs |= _ixl << 160;
return _ixs;
}
}
/// @title Asn1Decode
/// @custom:security-contact security@taiko.xyz
library Asn1Decode {
using NodePtr for uint256;
using BytesUtils for bytes;
error NOT_TYPE_OCTET_STRING();
error NOT_A_CONSTRUCTED_TYPE();
/*
* @dev Get the root node. First step in traversing an ASN1 structure
* @param der The DER-encoded ASN1 structure
* @return A pointer to the outermost node
*/
function root(bytes memory der) internal pure returns (uint256) {
return _readNodeLength(der, 0);
}
/*
* @dev Get the root node of an ASN1 structure that's within an octet string value
* @param der The DER-encoded ASN1 structure
* @return A pointer to the outermost node
*/
function rootOfOctetStringAt(
bytes memory der,
uint256 ptr
)
internal
pure
returns (uint256)
{
require(der[ptr.ixs()] == 0x04, NOT_TYPE_OCTET_STRING());
return _readNodeLength(der, ptr.ixf());
}
/*
* @dev Get the next sibling node
* @param der The DER-encoded ASN1 structure
* @param ptr Points to the indices of the current node
* @return A pointer to the next sibling node
*/
function nextSiblingOf(bytes memory der, uint256 ptr) internal pure returns (uint256) {
return _readNodeLength(der, ptr.ixl() + 1);
}
/*
* @dev Get the first child node of the current node
* @param der The DER-encoded ASN1 structure
* @param ptr Points to the indices of the current node
* @return A pointer to the first child node
*/
function firstChildOf(bytes memory der, uint256 ptr) internal pure returns (uint256) {
require(der[ptr.ixs()] & 0x20 == 0x20, NOT_A_CONSTRUCTED_TYPE());
return _readNodeLength(der, ptr.ixf());
}
/*
* @dev Extract value of node from DER-encoded structure
* @param der The der-encoded ASN1 structure
* @param ptr Points to the indices of the current node
* @return Value bytes of node
*/
function bytesAt(bytes memory der, uint256 ptr) internal pure returns (bytes memory) {
return der.substring(ptr.ixf(), ptr.ixl() + 1 - ptr.ixf());
}
/*
* @dev Extract entire node from DER-encoded structure
* @param der The DER-encoded ASN1 structure
* @param ptr Points to the indices of the current node
* @return All bytes of node
*/
function allBytesAt(bytes memory der, uint256 ptr) internal pure returns (bytes memory) {
return der.substring(ptr.ixs(), ptr.ixl() + 1 - ptr.ixs());
}
function keccakOfBytesAt(bytes memory der, uint256 ptr) internal pure returns (bytes32) {
return der.keccak(ptr.ixf(), ptr.ixl() + 1 - ptr.ixf());
}
function keccakOfAllBytesAt(
bytes memory der,
uint256 ptr
)
internal
pure
returns (bytes32)
{
return der.keccak(ptr.ixs(), ptr.ixl() + 1 - ptr.ixs());
}
function _readNodeLength(bytes memory der, uint256 ix) private pure returns (uint256) {
uint256 length;
uint80 ixFirstContentByte;
uint80 ixLastContentByte;
if ((der[ix + 1] & 0x80) == 0) {
length = uint8(der[ix + 1]);
ixFirstContentByte = uint80(ix + 2);
ixLastContentByte = uint80(ixFirstContentByte + length - 1);
} else {
uint8 lengthbytesLength = uint8(der[ix + 1] & 0x7F);
if (lengthbytesLength == 1) {
length = der.readUint8(ix + 2);
} else if (lengthbytesLength == 2) {
length = der.readUint16(ix + 2);
} else {
length = uint256(
der.readBytesN(ix + 2, lengthbytesLength) >> (32 - lengthbytesLength) * 8
);
}
ixFirstContentByte = uint80(ix + 2 + lengthbytesLength);
ixLastContentByte = uint80(ixFirstContentByte + length - 1);
}
return NodePtr.getPtr(ix, ixFirstContentByte, ixLastContentByte);
}
}
contracts/layer1/automata-attestation/utils/BytesUtils.sol
// SPDX-License-Identifier: BSD 2-Clause License
pragma solidity ^0.8.24;
// Inspired by ensdomains/dnssec-oracle - BSD-2-Clause license
// https://github.com/ensdomains/dnssec-oracle/blob/master/contracts/BytesUtils.sol
/// @title BytesUtils
/// @custom:security-contact security@taiko.xyz
library BytesUtils {
error INVALID_OFFSET();
error INVALID_IDX();
error UNEXPECTED_LEN();
error UNEXPECTED_IDX();
error UNEXPECTED_OFFSET();
/*
* @dev Returns the keccak-256 hash of a byte range.
* @param self The byte string to hash.
* @param offset The position to start hashing at.
* @param len The number of bytes to hash.
* @return The hash of the byte range.
*/
function keccak(
bytes memory self,
uint256 offset,
uint256 len
)
internal
pure
returns (bytes32 ret)
{
require(offset + len <= self.length, INVALID_OFFSET());
assembly {
ret := keccak256(add(add(self, 32), offset), len)
}
}
/*
* @dev Returns true if the two byte ranges are equal.
* @param self The first byte range to compare.
* @param offset The offset into the first byte range.
* @param other The second byte range to compare.
* @param otherOffset The offset into the second byte range.
* @param len The number of bytes to compare
* @return true if the byte ranges are equal, false otherwise.
*/
function equals(
bytes memory self,
uint256 offset,
bytes memory other,
uint256 otherOffset,
uint256 len
)
internal
pure
returns (bool)
{
return keccak(self, offset, len) == keccak(other, otherOffset, len);
}
/*
* @dev Returns the 8-bit number at the specified index of self.
* @param self The byte string.
* @param idx The index into the bytes
* @return The specified 8 bits of the string, interpreted as an integer.
*/
function readUint8(bytes memory self, uint256 idx) internal pure returns (uint8 ret) {
return uint8(self[idx]);
}
/*
* @dev Returns the 16-bit number at the specified index of self.
* @param self The byte string.
* @param idx The index into the bytes
* @return The specified 16 bits of the string, interpreted as an integer.
*/
function readUint16(bytes memory self, uint256 idx) internal pure returns (uint16 ret) {
require(idx + 2 <= self.length, INVALID_IDX());
assembly {
ret := and(mload(add(add(self, 2), idx)), 0xFFFF)
}
}
/*
* @dev Returns the n byte value at the specified index of self.
* @param self The byte string.
* @param idx The index into the bytes.
* @param len The number of bytes.
* @return The specified 32 bytes of the string.
*/
function readBytesN(
bytes memory self,
uint256 idx,
uint256 len
)
internal
pure
returns (bytes32 ret)
{
require(len <= 32, UNEXPECTED_LEN());
require(idx + len <= self.length, UNEXPECTED_IDX());
assembly {
let mask := not(sub(exp(256, sub(32, len)), 1))
ret := and(mload(add(add(self, 32), idx)), mask)
}
}
function memcpy(uint256 dest, uint256 src, uint256 len) private pure {
assembly {
mcopy(dest, src, len)
}
}
/*
* @dev Copies a substring into a new byte string.
* @param self The byte string to copy from.
* @param offset The offset to start copying at.
* @param len The number of bytes to copy.
*/
function substring(
bytes memory self,
uint256 offset,
uint256 len
)
internal
pure
returns (bytes memory)
{
require(offset + len <= self.length, UNEXPECTED_OFFSET());
bytes memory ret = new bytes(len);
uint256 dest;
uint256 src;
assembly {
dest := add(ret, 32)
src := add(add(self, 32), offset)
}
memcpy(dest, src, len);
return ret;
}
function compareBytes(bytes memory a, bytes memory b) internal pure returns (bool) {
return keccak256(a) == keccak256(b);
}
}
contracts/layer1/automata-attestation/utils/X509DateUtils.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title X509DateUtils
/// @custom:security-contact security@taiko.xyz
library X509DateUtils {
function toTimestamp(bytes memory x509Time) internal pure returns (uint256) {
uint16 yrs;
uint8 mnths;
uint8 dys;
uint8 hrs;
uint8 mins;
uint8 secs;
uint8 offset;
if (x509Time.length == 13) {
if (uint8(x509Time[0]) - 48 < 5) yrs += 2000;
else yrs += 1900;
} else {
yrs += (uint8(x509Time[0]) - 48) * 1000 + (uint8(x509Time[1]) - 48) * 100;
offset = 2;
}
yrs += (uint8(x509Time[offset + 0]) - 48) * 10 + uint8(x509Time[offset + 1]) - 48;
mnths = (uint8(x509Time[offset + 2]) - 48) * 10 + uint8(x509Time[offset + 3]) - 48;
dys += (uint8(x509Time[offset + 4]) - 48) * 10 + uint8(x509Time[offset + 5]) - 48;
hrs += (uint8(x509Time[offset + 6]) - 48) * 10 + uint8(x509Time[offset + 7]) - 48;
mins += (uint8(x509Time[offset + 8]) - 48) * 10 + uint8(x509Time[offset + 9]) - 48;
secs += (uint8(x509Time[offset + 10]) - 48) * 10 + uint8(x509Time[offset + 11]) - 48;
return toUnixTimestamp(yrs, mnths, dys, hrs, mins, secs);
}
function toUnixTimestamp(
uint16 year,
uint8 month,
uint8 day,
uint8 hour,
uint8 minute,
uint8 second
)
internal
pure
returns (uint256)
{
uint256 timestamp = 0;
for (uint16 i = 1970; i < year; ++i) {
if (isLeapYear(i)) {
timestamp += 31_622_400; // Leap year in seconds
} else {
timestamp += 31_536_000; // Normal year in seconds
}
}
uint8[12] memory monthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
if (isLeapYear(year)) monthDays[1] = 29;
for (uint8 i = 1; i < month; ++i) {
timestamp += uint256(monthDays[i - 1]) * 86_400; // Days in seconds
}
timestamp += uint256(day - 1) * 86_400; // Days in seconds
timestamp += uint256(hour) * 3600; // Hours in seconds
timestamp += uint256(minute) * 60; // Minutes in seconds
timestamp += second;
return timestamp;
}
function isLeapYear(uint16 year) internal pure returns (bool) {
if (year % 4 != 0) return false;
if (year % 100 != 0) return true;
if (year % 400 != 0) return false;
return true;
}
}
contracts/shared/common/EssentialContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./IResolver.sol";
import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
/// @title EssentialContract
/// @custom:security-contact security@taiko.xyz
abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable {
// ---------------------------------------------------------------
// Constants and Immutable Variables
// ---------------------------------------------------------------
uint8 internal constant _FALSE = 1;
uint8 internal constant _TRUE = 2;
address internal immutable __resolver;
// ---------------------------------------------------------------
// State Variables
// ---------------------------------------------------------------
uint256[50] private __gapFromOldAddressResolver;
/// @dev Slot 1.
uint8 internal __reentry;
uint8 internal __paused;
uint256[49] private __gap;
// ---------------------------------------------------------------
// Events
// ---------------------------------------------------------------
/// @notice Emitted when the contract is paused.
/// @param account The account that paused the contract.
event Paused(address account);
/// @notice Emitted when the contract is unpaused.
/// @param account The account that unpaused the contract.
event Unpaused(address account);
error INVALID_PAUSE_STATUS();
error FUNC_NOT_IMPLEMENTED();
error REENTRANT_CALL();
error ACCESS_DENIED();
error ZERO_ADDRESS();
error ZERO_VALUE();
// ---------------------------------------------------------------
// Modifiers
// ---------------------------------------------------------------
/// @dev Modifier that ensures the caller is either the owner or a specified address.
/// @param _addr The address to check against.
modifier onlyFromOwnerOr(address _addr) {
_checkOwnerOr(_addr);
_;
}
/// @dev Modifier that reverts the function call, indicating it is not implemented.
modifier notImplemented() {
revert FUNC_NOT_IMPLEMENTED();
_;
}
/// @dev Modifier that prevents reentrant calls to a function.
modifier nonReentrant() {
_checkReentrancy();
_storeReentryLock(_TRUE);
_;
_storeReentryLock(_FALSE);
}
/// @dev Modifier that allows function execution only when the contract is paused.
modifier whenPaused() {
_checkPaused();
_;
}
/// @dev Modifier that allows function execution only when the contract is not paused.
modifier whenNotPaused() {
_checkNotPaused();
_;
}
/// @dev Modifier that ensures the provided address is not the zero address.
/// @param _addr The address to check.
modifier nonZeroAddr(address _addr) {
_checkNonZeroAddr(_addr);
_;
}
/// @dev Modifier that ensures the provided value is not zero.
/// @param _value The value to check.
modifier nonZeroValue(uint256 _value) {
_checkNonZeroValue(_value);
_;
}
/// @dev Modifier that ensures the provided bytes32 value is not zero.
/// @param _value The bytes32 value to check.
modifier nonZeroBytes32(bytes32 _value) {
_checkNonZeroBytes32(_value);
_;
}
/// @dev Modifier that ensures the caller is either of the two specified addresses.
/// @param _addr1 The first address to check against.
/// @param _addr2 The second address to check against.
modifier onlyFromEither(address _addr1, address _addr2) {
_checkFromEither(_addr1, _addr2);
_;
}
/// @dev Modifier that ensures the caller is the specified address.
/// @param _addr The address to check against.
modifier onlyFrom(address _addr) {
_checkFrom(_addr);
_;
}
/// @dev Modifier that ensures the caller is the specified address.
/// @param _addr The address to check against.
modifier onlyFromOptional(address _addr) {
_checkFromOptional(_addr);
_;
}
// ---------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------
constructor() {
_disableInitializers();
}
// ---------------------------------------------------------------
// External & Public Functions
// ---------------------------------------------------------------
/// @notice Pauses the contract.
function pause() public whenNotPaused {
_pause();
emit Paused(msg.sender);
// We call the authorize function here to avoid:
// Warning (5740): Unreachable code.
_authorizePause(msg.sender, true);
}
/// @notice Unpauses the contract.
function unpause() public whenPaused {
_unpause();
emit Unpaused(msg.sender);
// We call the authorize function here to avoid:
// Warning (5740): Unreachable code.
_authorizePause(msg.sender, false);
}
function impl() public view returns (address) {
return _getImplementation();
}
/// @notice Returns true if the contract is paused, and false otherwise.
/// @return true if paused, false otherwise.
function paused() public view virtual returns (bool) {
return __paused == _TRUE;
}
function inNonReentrant() public view returns (bool) {
return _loadReentryLock() == _TRUE;
}
/// @notice Returns the address of this contract.
/// @return The address of this contract.
function resolver() public view virtual returns (address) {
return __resolver;
}
// ---------------------------------------------------------------
// Internal Functions
// ---------------------------------------------------------------
/// @notice Initializes the contract.
/// @param _owner The owner of this contract. msg.sender will be used if this value is zero.
function __Essential_init(address _owner) internal virtual onlyInitializing {
__Context_init();
_transferOwnership(_owner == address(0) ? msg.sender : _owner);
__paused = _FALSE;
}
function _pause() internal virtual {
__paused = _TRUE;
}
function _unpause() internal virtual {
__paused = _FALSE;
}
function _authorizeUpgrade(address) internal virtual override onlyOwner { }
function _authorizePause(address, bool) internal virtual onlyOwner { }
// Stores the reentry lock
function _storeReentryLock(uint8 _reentry) internal virtual {
__reentry = _reentry;
}
// Loads the reentry lock
function _loadReentryLock() internal view virtual returns (uint8 reentry_) {
reentry_ = __reentry;
}
// ---------------------------------------------------------------
// Private Functions
// ---------------------------------------------------------------
function _checkOwnerOr(address _addr) private view {
require(msg.sender == owner() || msg.sender == _addr, ACCESS_DENIED());
}
function _checkReentrancy() private view {
require(_loadReentryLock() != _TRUE, REENTRANT_CALL());
}
function _checkPaused() private view {
require(paused(), INVALID_PAUSE_STATUS());
}
function _checkNotPaused() private view {
require(!paused(), INVALID_PAUSE_STATUS());
}
function _checkNonZeroAddr(address _addr) private pure {
require(_addr != address(0), ZERO_ADDRESS());
}
function _checkNonZeroValue(uint256 _value) private pure {
require(_value != 0, ZERO_VALUE());
}
function _checkNonZeroBytes32(bytes32 _value) private pure {
require(_value != 0, ZERO_VALUE());
}
function _checkFromEither(address _addr1, address _addr2) private view {
require(msg.sender == _addr1 || msg.sender == _addr2, ACCESS_DENIED());
}
function _checkFrom(address _addr) private view {
require(msg.sender == _addr, ACCESS_DENIED());
}
function _checkFromOptional(address _addr) private view {
require(_addr == address(0) || msg.sender == _addr, ACCESS_DENIED());
}
}
contracts/shared/common/IResolver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title IResolver
/// @notice This contract acts as a bridge for name-to-address resolution.
/// @custom:security-contact security@taiko.xyz
interface IResolver {
error RESOLVED_TO_ZERO_ADDRESS();
/// @notice Resolves a name to its address deployed on a specified chain.
/// @param _chainId The chainId of interest.
/// @param _name Name whose address is to be resolved.
/// @param _allowZeroAddress If set to true, does not throw if the resolved
/// address is `address(0)`.
/// @return Address associated with the given name on the specified
/// chain.
function resolve(
uint256 _chainId,
bytes32 _name,
bool _allowZeroAddress
)
external
view
returns (address);
}
node_modules/@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
import "./OwnableUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides 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} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function __Ownable2Step_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable2Step_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
node_modules/@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_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);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}
node_modules/@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
node_modules/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
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;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
node_modules/@openzeppelin/contracts/interfaces/IERC1967.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*
* _Available since v4.8.3._
*/
interface IERC1967 {
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
}
node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}
node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/IERC1967.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*/
abstract contract ERC1967Upgrade is IERC1967 {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}
node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}
node_modules/@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.0;
import "../../interfaces/draft-IERC1822.sol";
import "../ERC1967/ERC1967Upgrade.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
require(address(this) != __self, "Function must be called through delegatecall");
require(_getImplementation() == __self, "Function must be called through active proxy");
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
_;
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeTo(address newImplementation) public virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeTo} and {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal override onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
}
node_modules/@openzeppelin/contracts/utils/Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
node_modules/@openzeppelin/contracts/utils/StorageSlot.sol
// 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
}
}
}
node_modules/solady/src/utils/Base64.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library to encode strings in Base64.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol)
/// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <brecht@loopring.org>.
library Base64 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ENCODING / DECODING */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Encodes `data` using the base64 encoding described in RFC 4648.
/// See: https://datatracker.ietf.org/doc/html/rfc4648
/// @param fileSafe Whether to replace '+' with '-' and '/' with '_'.
/// @param noPadding Whether to strip away the padding.
function encode(bytes memory data, bool fileSafe, bool noPadding)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let dataLength := mload(data)
if dataLength {
// Multiply by 4/3 rounded up.
// The `shl(2, ...)` is equivalent to multiplying by 4.
let encodedLength := shl(2, div(add(dataLength, 2), 3))
// Set `result` to point to the start of the free memory.
result := mload(0x40)
// Store the table into the scratch space.
// Offsetted by -1 byte so that the `mload` will load the character.
// We will rewrite the free memory pointer at `0x40` later with
// the allocated size.
// The magic constant 0x0670 will turn "-_" into "+/".
mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef")
mstore(0x3f, xor("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0670)))
// Skip the first slot, which stores the length.
let ptr := add(result, 0x20)
let end := add(ptr, encodedLength)
let dataEnd := add(add(0x20, data), dataLength)
let dataEndValue := mload(dataEnd) // Cache the value at the `dataEnd` slot.
mstore(dataEnd, 0x00) // Zeroize the `dataEnd` slot to clear dirty bits.
// Run over the input, 3 bytes at a time.
for {} 1 {} {
data := add(data, 3) // Advance 3 bytes.
let input := mload(data)
// Write 4 bytes. Optimized for fewer stack operations.
mstore8(0, mload(and(shr(18, input), 0x3F)))
mstore8(1, mload(and(shr(12, input), 0x3F)))
mstore8(2, mload(and(shr(6, input), 0x3F)))
mstore8(3, mload(and(input, 0x3F)))
mstore(ptr, mload(0x00))
ptr := add(ptr, 4) // Advance 4 bytes.
if iszero(lt(ptr, end)) { break }
}
mstore(dataEnd, dataEndValue) // Restore the cached value at `dataEnd`.
mstore(0x40, add(end, 0x20)) // Allocate the memory.
// Equivalent to `o = [0, 2, 1][dataLength % 3]`.
let o := div(2, mod(dataLength, 3))
// Offset `ptr` and pad with '='. We can simply write over the end.
mstore(sub(ptr, o), shl(240, 0x3d3d))
// Set `o` to zero if there is padding.
o := mul(iszero(iszero(noPadding)), o)
mstore(sub(ptr, o), 0) // Zeroize the slot after the string.
mstore(result, sub(encodedLength, o)) // Store the length.
}
}
}
/// @dev Encodes `data` using the base64 encoding described in RFC 4648.
/// Equivalent to `encode(data, false, false)`.
function encode(bytes memory data) internal pure returns (string memory result) {
result = encode(data, false, false);
}
/// @dev Encodes `data` using the base64 encoding described in RFC 4648.
/// Equivalent to `encode(data, fileSafe, false)`.
function encode(bytes memory data, bool fileSafe)
internal
pure
returns (string memory result)
{
result = encode(data, fileSafe, false);
}
/// @dev Decodes base64 encoded `data`.
///
/// Supports:
/// - RFC 4648 (both standard and file-safe mode).
/// - RFC 3501 (63: ',').
///
/// Does not support:
/// - Line breaks.
///
/// Note: For performance reasons,
/// this function will NOT revert on invalid `data` inputs.
/// Outputs for invalid inputs will simply be undefined behaviour.
/// It is the user's responsibility to ensure that the `data`
/// is a valid base64 encoded string.
function decode(string memory data) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
let dataLength := mload(data)
if dataLength {
let decodedLength := mul(shr(2, dataLength), 3)
for {} 1 {} {
// If padded.
if iszero(and(dataLength, 3)) {
let t := xor(mload(add(data, dataLength)), 0x3d3d)
// forgefmt: disable-next-item
decodedLength := sub(
decodedLength,
add(iszero(byte(30, t)), iszero(byte(31, t)))
)
break
}
// If non-padded.
decodedLength := add(decodedLength, sub(and(dataLength, 3), 1))
break
}
result := mload(0x40)
// Write the length of the bytes.
mstore(result, decodedLength)
// Skip the first slot, which stores the length.
let ptr := add(result, 0x20)
let end := add(ptr, decodedLength)
// Load the table into the scratch space.
// Constants are optimized for smaller bytecode with zero gas overhead.
// `m` also doubles as the mask of the upper 6 bits.
let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc
mstore(0x5b, m)
mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064)
mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4)
for {} 1 {} {
// Read 4 bytes.
data := add(data, 4)
let input := mload(data)
// Write 3 bytes.
// forgefmt: disable-next-item
mstore(ptr, or(
and(m, mload(byte(28, input))),
shr(6, or(
and(m, mload(byte(29, input))),
shr(6, or(
and(m, mload(byte(30, input))),
shr(6, mload(byte(31, input)))
))
))
))
ptr := add(ptr, 3)
if iszero(lt(ptr, end)) { break }
}
mstore(0x40, add(end, 0x20)) // Allocate the memory.
mstore(end, 0) // Zeroize the slot after the bytes.
mstore(0x60, 0) // Restore the zero slot.
}
}
}
}
Compiler Settings
{"viaIR":true,"remappings":["openzeppelin/=node_modules/@openzeppelin/","@openzeppelin/=node_modules/@openzeppelin/","@openzeppelin-upgrades/contracts/=node_modules/@openzeppelin/contracts-upgradeable/","@risc0/contracts/=node_modules/risc0-ethereum/contracts/src/","@solady/=node_modules/solady/","solady/src/=node_modules/solady/src/","solady/utils/=node_modules/solady/src/utils/","@optimism/=node_modules/optimism/","@sp1-contracts/=node_modules/sp1-contracts/contracts/","forge-std/=node_modules/forge-std/","@p256-verifier/contracts/=node_modules/p256-verifier/src/","@eth-fabric/urc/=node_modules/urc/src/","ds-test/=node_modules/ds-test/","src/=contracts/","test/=test/","script/=script/","optimism/=node_modules/optimism/","p256-verifier/=node_modules/p256-verifier/","risc0-ethereum/=node_modules/risc0-ethereum/","sp1-contracts/=node_modules/sp1-contracts/","urc/=node_modules/urc/"],"outputSelection":{"*":{"*":["*"],"":["*"]}},"optimizer":{"runs":200,"enabled":true},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"libraries":{"contracts/layer1/core/libs/LibInboxSetup.sol":{"LibInboxSetup":"0xf88Ef5437749A225621101BE8C1BE1A0cE967758"},"contracts/layer1/core/libs/LibForcedInclusion.sol":{"LibForcedInclusion":"0xd1a27F331c17eD8Cbb6DAbce67A42d6b8a6B0e14"}},"evmVersion":"prague"}
Contract ABI
[{"type":"error","name":"ACCESS_DENIED","inputs":[]},{"type":"error","name":"FUNC_NOT_IMPLEMENTED","inputs":[]},{"type":"error","name":"INVALID_PAUSE_STATUS","inputs":[]},{"type":"error","name":"REENTRANT_CALL","inputs":[]},{"type":"error","name":"UNEXPECTED_OFFSET","inputs":[]},{"type":"error","name":"V3PARSER_INVALID_CERTIFICATION_CHAIN_DATA","inputs":[]},{"type":"error","name":"V3PARSER_INVALID_CERTIFICATION_CHAIN_SIZE","inputs":[]},{"type":"error","name":"V3PARSER_INVALID_ECDSA_SIGNATURE","inputs":[]},{"type":"error","name":"V3PARSER_INVALID_QEAUTHDATA_SIZE","inputs":[]},{"type":"error","name":"V3PARSER_INVALID_QEREPORT_LENGTN","inputs":[]},{"type":"error","name":"V3PARSER_INVALID_QUOTE_LENGTN","inputs":[]},{"type":"error","name":"V3PARSER_INVALID_QUOTE_MEMBER_LENGTN","inputs":[]},{"type":"error","name":"V3PARSER_UNSUPPORT_CERTIFICATION_TYPE","inputs":[]},{"type":"error","name":"ZERO_ADDRESS","inputs":[]},{"type":"error","name":"ZERO_VALUE","inputs":[]},{"type":"event","name":"AdminChanged","inputs":[{"type":"address","name":"previousAdmin","internalType":"address","indexed":false},{"type":"address","name":"newAdmin","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"BeaconUpgraded","inputs":[{"type":"address","name":"beacon","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"type":"uint8","name":"version","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"LocalReportCheckToggled","inputs":[{"type":"bool","name":"checkLocalEnclaveReport","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"MrEnclaveUpdated","inputs":[{"type":"bytes32","name":"mrEnclave","internalType":"bytes32","indexed":true},{"type":"bool","name":"trusted","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"MrSignerUpdated","inputs":[{"type":"bytes32","name":"mrSigner","internalType":"bytes32","indexed":true},{"type":"bool","name":"trusted","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferStarted","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Paused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"QeIdentityConfigured","inputs":[{"type":"tuple","name":"qeIdentityInput","internalType":"struct EnclaveIdStruct.EnclaveId","indexed":false,"components":[{"type":"bytes4","name":"miscselect","internalType":"bytes4"},{"type":"bytes4","name":"miscselectMask","internalType":"bytes4"},{"type":"uint16","name":"isvprodid","internalType":"uint16"},{"type":"bytes16","name":"attributes","internalType":"bytes16"},{"type":"bytes16","name":"attributesMask","internalType":"bytes16"},{"type":"bytes32","name":"mrsigner","internalType":"bytes32"},{"type":"tuple[]","name":"tcbLevels","internalType":"struct EnclaveIdStruct.TcbLevel[]","components":[{"type":"tuple","name":"tcb","internalType":"struct EnclaveIdStruct.TcbObj","components":[{"type":"uint16","name":"isvsvn","internalType":"uint16"}]},{"type":"uint8","name":"tcbStatus","internalType":"enum EnclaveIdStruct.EnclaveIdStatus"}]}]}],"anonymous":false},{"type":"event","name":"RevokedCertSerialNumAdded","inputs":[{"type":"uint256","name":"index","internalType":"uint256","indexed":true},{"type":"bytes","name":"serialNum","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"RevokedCertSerialNumRemoved","inputs":[{"type":"uint256","name":"index","internalType":"uint256","indexed":true},{"type":"bytes","name":"serialNum","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"TcbInfoJsonConfigured","inputs":[{"type":"string","name":"fmspc","internalType":"string","indexed":true},{"type":"tuple","name":"tcbInfoInput","internalType":"struct TCBInfoStruct.TCBInfo","indexed":false,"components":[{"type":"string","name":"pceid","internalType":"string"},{"type":"string","name":"fmspc","internalType":"string"},{"type":"tuple[]","name":"tcbLevels","internalType":"struct TCBInfoStruct.TCBLevelObj[]","components":[{"type":"uint256","name":"pcesvn","internalType":"uint256"},{"type":"uint8[]","name":"sgxTcbCompSvnArr","internalType":"uint8[]"},{"type":"uint8","name":"status","internalType":"enum TCBInfoStruct.TCBStatus"}]}]}],"anonymous":false},{"type":"event","name":"Unpaused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Upgraded","inputs":[{"type":"address","name":"implementation","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addRevokedCertSerialNum","inputs":[{"type":"uint256","name":"index","internalType":"uint256"},{"type":"bytes[]","name":"serialNumBatch","internalType":"bytes[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"checkLocalEnclaveReport","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"configureQeIdentityJson","inputs":[{"type":"tuple","name":"qeIdentityInput","internalType":"struct EnclaveIdStruct.EnclaveId","components":[{"type":"bytes4","name":"miscselect","internalType":"bytes4"},{"type":"bytes4","name":"miscselectMask","internalType":"bytes4"},{"type":"uint16","name":"isvprodid","internalType":"uint16"},{"type":"bytes16","name":"attributes","internalType":"bytes16"},{"type":"bytes16","name":"attributesMask","internalType":"bytes16"},{"type":"bytes32","name":"mrsigner","internalType":"bytes32"},{"type":"tuple[]","name":"tcbLevels","internalType":"struct EnclaveIdStruct.TcbLevel[]","components":[{"type":"tuple","name":"tcb","internalType":"struct EnclaveIdStruct.TcbObj","components":[{"type":"uint16","name":"isvsvn","internalType":"uint16"}]},{"type":"uint8","name":"tcbStatus","internalType":"enum EnclaveIdStruct.EnclaveIdStatus"}]}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"configureTcbInfoJson","inputs":[{"type":"string","name":"fmspc","internalType":"string"},{"type":"tuple","name":"tcbInfoInput","internalType":"struct TCBInfoStruct.TCBInfo","components":[{"type":"string","name":"pceid","internalType":"string"},{"type":"string","name":"fmspc","internalType":"string"},{"type":"tuple[]","name":"tcbLevels","internalType":"struct TCBInfoStruct.TCBLevelObj[]","components":[{"type":"uint256","name":"pcesvn","internalType":"uint256"},{"type":"uint8[]","name":"sgxTcbCompSvnArr","internalType":"uint8[]"},{"type":"uint8","name":"status","internalType":"enum TCBInfoStruct.TCBStatus"}]}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"impl","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"inNonReentrant","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"init","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"sigVerifyLibAddr","internalType":"address"},{"type":"address","name":"pemCertLibAddr","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pause","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPEMCertChainLib"}],"name":"pemCertLib","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"pendingOwner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"proxiableUUID","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes4","name":"miscselect","internalType":"bytes4"},{"type":"bytes4","name":"miscselectMask","internalType":"bytes4"},{"type":"uint16","name":"isvprodid","internalType":"uint16"},{"type":"bytes16","name":"attributes","internalType":"bytes16"},{"type":"bytes16","name":"attributesMask","internalType":"bytes16"},{"type":"bytes32","name":"mrsigner","internalType":"bytes32"}],"name":"qeIdentity","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeRevokedCertSerialNum","inputs":[{"type":"uint256","name":"index","internalType":"uint256"},{"type":"bytes[]","name":"serialNumBatch","internalType":"bytes[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"resolver","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"revoked","internalType":"bool"}],"name":"serialNumIsRevoked","inputs":[{"type":"uint256","name":"idx","internalType":"uint256"},{"type":"bytes","name":"serialNum","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMrEnclave","inputs":[{"type":"bytes32","name":"_mrEnclave","internalType":"bytes32"},{"type":"bool","name":"_trusted","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMrSigner","inputs":[{"type":"bytes32","name":"_mrSigner","internalType":"bytes32"},{"type":"bool","name":"_trusted","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ISigVerifyLib"}],"name":"sigVerifyLib","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"pceid","internalType":"string"},{"type":"string","name":"fmspc","internalType":"string"}],"name":"tcbInfo","inputs":[{"type":"string","name":"fmspc","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"toggleLocalReportCheck","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"trusted","internalType":"bool"}],"name":"trustedUserMrEnclave","inputs":[{"type":"bytes32","name":"enclave","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"trusted","internalType":"bool"}],"name":"trustedUserMrSigner","inputs":[{"type":"bytes32","name":"signer","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unpause","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"upgradeTo","inputs":[{"type":"address","name":"newImplementation","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"upgradeToAndCall","inputs":[{"type":"address","name":"newImplementation","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"success","internalType":"bool"}],"name":"verifyAttestation","inputs":[{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"},{"type":"bytes","name":"","internalType":"bytes"}],"name":"verifyParsedQuote","inputs":[{"type":"tuple","name":"v3quote","internalType":"struct V3Struct.ParsedV3QuoteStruct","components":[{"type":"tuple","name":"header","internalType":"struct V3Struct.Header","components":[{"type":"bytes2","name":"version","internalType":"bytes2"},{"type":"bytes2","name":"attestationKeyType","internalType":"bytes2"},{"type":"bytes4","name":"teeType","internalType":"bytes4"},{"type":"bytes2","name":"qeSvn","internalType":"bytes2"},{"type":"bytes2","name":"pceSvn","internalType":"bytes2"},{"type":"bytes16","name":"qeVendorId","internalType":"bytes16"},{"type":"bytes20","name":"userData","internalType":"bytes20"}]},{"type":"tuple","name":"localEnclaveReport","internalType":"struct V3Struct.EnclaveReport","components":[{"type":"bytes16","name":"cpuSvn","internalType":"bytes16"},{"type":"bytes4","name":"miscSelect","internalType":"bytes4"},{"type":"bytes28","name":"reserved1","internalType":"bytes28"},{"type":"bytes16","name":"attributes","internalType":"bytes16"},{"type":"bytes32","name":"mrEnclave","internalType":"bytes32"},{"type":"bytes32","name":"reserved2","internalType":"bytes32"},{"type":"bytes32","name":"mrSigner","internalType":"bytes32"},{"type":"bytes","name":"reserved3","internalType":"bytes"},{"type":"uint16","name":"isvProdId","internalType":"uint16"},{"type":"uint16","name":"isvSvn","internalType":"uint16"},{"type":"bytes","name":"reserved4","internalType":"bytes"},{"type":"bytes","name":"reportData","internalType":"bytes"}]},{"type":"tuple","name":"v3AuthData","internalType":"struct V3Struct.ECDSAQuoteV3AuthData","components":[{"type":"bytes","name":"ecdsa256BitSignature","internalType":"bytes"},{"type":"bytes","name":"ecdsaAttestationKey","internalType":"bytes"},{"type":"tuple","name":"pckSignedQeReport","internalType":"struct V3Struct.EnclaveReport","components":[{"type":"bytes16","name":"cpuSvn","internalType":"bytes16"},{"type":"bytes4","name":"miscSelect","internalType":"bytes4"},{"type":"bytes28","name":"reserved1","internalType":"bytes28"},{"type":"bytes16","name":"attributes","internalType":"bytes16"},{"type":"bytes32","name":"mrEnclave","internalType":"bytes32"},{"type":"bytes32","name":"reserved2","internalType":"bytes32"},{"type":"bytes32","name":"mrSigner","internalType":"bytes32"},{"type":"bytes","name":"reserved3","internalType":"bytes"},{"type":"uint16","name":"isvProdId","internalType":"uint16"},{"type":"uint16","name":"isvSvn","internalType":"uint16"},{"type":"bytes","name":"reserved4","internalType":"bytes"},{"type":"bytes","name":"reportData","internalType":"bytes"}]},{"type":"bytes","name":"qeReportSignature","internalType":"bytes"},{"type":"tuple","name":"qeAuthData","internalType":"struct V3Struct.QEAuthData","components":[{"type":"uint16","name":"parsedDataSize","internalType":"uint16"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"tuple","name":"certification","internalType":"struct V3Struct.CertificationData","components":[{"type":"uint16","name":"certType","internalType":"uint16"},{"type":"uint32","name":"certDataSize","internalType":"uint32"},{"type":"bytes[3]","name":"decodedCertDataArray","internalType":"bytes[3]"}]}]}]}]}]
Contract Creation Code
0x60c080604052346100e357306080525f549060ff8260081c16610091575060ff80821603610057575b60405161574a90816100e882396080518181816108a601528181610fc301526110e3015260a051816102550152f35b60ff90811916175f557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160ff8152a15f610028565b62461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806301d711f41461021457806304f3bcec1461020f5780630570e1fc1461020a578063089a168f146102055780630d23d71b14610200578063123ac29e146101fb578063184b9559146101f65780631f3be096146101f15780633075db56146101ec57806332f555ec146101e75780633659cfe6146101e25780633a343014146101dd5780633f4ba83a146101d85780634bc7eea4146101d35780634c0977a9146101ce5780634f1ef286146101c957806352d1902d146101c457806354e21913146101bf5780635c975abb146101ba578063610de480146101b5578063715018a6146101b0578063769d87e7146101ab57806379ba5097146101a657806383801580146101a15780638456cb591461019c5780638abf6077146101975780638da5cb5b14610192578063b684252f1461018d578063cf12f55514610188578063e2e2829414610183578063e30c39781461017e5763f2fde38b14610179575f80fd5b6116ae565b611686565b61161b565b6115ac565b611513565b6114eb565b6114b7565b61144b565b6113de565b61135a565b611314565b6112af565b6111f1565b6111c3565b611194565b6110d1565b610f8b565b610ef0565b610a4c565b6109b4565b61093e565b610888565b610859565b610836565b610774565b61061b565b61044a565b610422565b6102e9565b610284565b610240565b3461023c575f36600319011261023c5760fc546040516001600160a01b039091168152602090f35b5f80fd5b3461023c575f36600319011261023c576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461023c575f36600319011261023c57602060ff60fc5460a01c166040519015158152f35b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b6040906102e693921515815281602082015201906102a9565b90565b3461023c57602036600319011261023c576004356001600160401b03811161023c5760031981360301610120811261023c5760e06040519161032a83610c53565b1261023c5760405161033b81610c6e565b6103478360040161171a565b81526103556024840161171a565b602082015260448301356103688161172f565b60408201526103796064840161171a565b606082015261038a6084840161171a565b608082015260a483013561039d8161174c565b60a08201526103ae60c48401611769565b60c0820152815260e48201356001600160401b03811161023c576103d890600436918501016117a7565b60208201526101048201356001600160401b03811161023c5761040e92600461040492369201016119b9565b604082015261330a565b9061041e604051928392836102cd565b0390f35b3461023c575f36600319011261023c5760fb546040516001600160a01b039091168152602090f35b3461023c57602036600319011261023c576004356001600160401b03811161023c57806004019060e0600319823603011261023c577f8867fcb26463d2f77f8c8f24316221d64d8b4821bf4dea1b4c9b83d4ba271c45916105c86105c260c46105d4946104b561361a565b84356104c08161172f565b60e01c63ffffffff196101015416176101015561050b60248201356104e48161172f565b67ffffffff0000000080610101549260c01c16169067ffffffff0000000019161761010155565b61053961051a60448301611aa1565b61ffff60401b610101549160401b169061ffff60401b19161761010155565b61058661054860648301611aab565b61010180546fffffffffffffffffffffffffffffffff60501b191660309290921c6fffffffffffffffffffffffffffffffff60501b16919091179055565b6105ad61059560848301611aab565b60801c6001600160801b031961010254161761010255565b6105bb60a482013561010355565b0183611ab5565b90611b9d565b60405191829182611cef565b0390a1005b600435906001600160a01b038216820361023c57565b602435906001600160a01b038216820361023c57565b604435906001600160a01b038216820361023c57565b3461023c57606036600319011261023c576106346105d9565b61069361063f6105ef565b610647610605565b905f549361067961066361065f8760ff9060081c1690565b1590565b80968197610711575b81156106f1575b50611db0565b8461068a600160ff195f5416175f55565b6106da57611e13565b61069957005b6106a75f5461ff0019165f55565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989080602081016105d4565b6106ec6101005f5461ff001916175f55565b611e13565b303b15915081610703575b505f610673565b60ff1660011490505f6106fc565b600160ff821610915061066c565b604060031982011261023c57600435916024356001600160401b03811161023c578260238201121561023c578060040135926001600160401b03841161023c5760248460051b8301011161023c576024019190565b3461023c576107823661071f565b909161078c61361a565b5f5b82811061079757005b600190825f5260ff60205260ff6107bc60405f206107b684888a611eda565b90611efa565b54161561083157825f5260ff6020526107ea6107e060405f206107b684888a611eda565b805460ff19169055565b827fee365795c95effb059e7128967d8e0dce7b2eaaf750bb4c422df5411fb8aedfd610817838789611eda565b9061082760405192839283611f33565b0390a25b0161078e565b61082b565b3461023c575f36600319011261023c576020600260ff60c9541614604051908152f35b3461023c57602036600319011261023c576004355f5260fe602052602060ff60405f2054166040519015158152f35b3461023c57602036600319011261023c576108a16105d9565b6108f87f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166108da30821415611f44565b5f5160206156f55f395f51905f52546001600160a01b031614611fa5565b61090061361a565b60405161092d91610912602083610cf6565b5f8252601f196109215f610d74565b0136602084013761378e565b005b610c3f565b8015150361023c57565b3461023c57604036600319011261023c576004357fe9c8da9c89154486636f96dbbf87f6cdf819637dda597383e5b1533b446b51d2602060243561098181610934565b61098961361a565b835f5260fd82526109a98160405f209060ff801983541691151516179055565b6040519015158152a2005b3461023c575f36600319011261023c576109de6109d9600260ff60c95460081c161490565b61384d565b61010060c95461ff0019161760c9557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a161092d61361a565b9181601f8401121561023c578235916001600160401b03831161023c576020838186019501011161023c57565b3461023c57604036600319011261023c576004356001600160401b03811161023c57610a7c903690600401610a1f565b602435916001600160401b03831161023c5782600401926060600319823603011261023c57610aa961361a565b6040518383823760208185810161010081520301902090610aca8580611ea8565b906001600160401b03821161092f57610aed82610ae78654610df5565b8661204e565b5f90601f8311600114610ba057610b8394610b7560447f540fc9dd1a61f44f6860558982bac073b37667cb331897eb59633910cfd038229996610b5187610b909b98610b7e986002985f92610b95575b50508160011b915f199060031b1c19161790565b84555b610b6e610b64602483018e611ea8565b9060018701612091565b018a61214d565b92909101612371565b612425565b926040519182918261249e565b0390a2005b013590505f80610b3d565b601f19831691610bb3865f5260205f2090565b925f5b818110610c27575060447f540fc9dd1a61f44f6860558982bac073b37667cb331897eb59633910cfd038229996600187610b7e97600297610b839c97610b909e9b610b759810610c0e575b505050811b018455610b54565b01355f19600384901b60f8161c191690555f8080610c01565b91936020600181928787013581550195019201610bb6565b634e487b7160e01b5f52604160045260245ffd5b606081019081106001600160401b0382111761092f57604052565b60e081019081106001600160401b0382111761092f57604052565b604081019081106001600160401b0382111761092f57604052565b61010081019081106001600160401b0382111761092f57604052565b608081019081106001600160401b0382111761092f57604052565b602081019081106001600160401b0382111761092f57604052565b90601f801991011681019081106001600160401b0382111761092f57604052565b60405190610d2761018083610cf6565b565b60405190610d2760c083610cf6565b60405190610d2761010083610cf6565b60405190610d27606083610cf6565b60405190610d2760e083610cf6565b90610d276040519283610cf6565b6001600160401b03811161092f57601f01601f191660200190565b929192610d9b82610d74565b91610da96040519384610cf6565b82948184528183011161023c578281602093845f960137010152565b805191908290602001825e015f815290565b6020610de99160405192838092610dc5565b61010081520301902090565b90600182811c92168015610e23575b6020831014610e0f57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610e04565b9060405191825f825492610e4084610df5565b8084529360018116908115610ea95750600114610e65575b50610d2792500383610cf6565b90505f9291925260205f20905f915b818310610e8d575050906020610d27928201015f610e58565b6020919350806001915483858901015201910190918492610e74565b905060209250610d2794915060ff191682840152151560051b8201015f610e58565b9091610ee26102e6936040845260408401906102a9565b9160208184039101526102a9565b3461023c57602036600319011261023c576004356001600160401b03811161023c573660238201121561023c576020610f36610f42923690602481600401359101610d8f565b60405192838092610dc5565b610100815203019020610f606001610f5983610e2d565b9201610e2d565b9061041e60405192839283610ecb565b9080601f8301121561023c578160206102e693359101610d8f565b604036600319011261023c57610f9f6105d9565b6024356001600160401b03811161023c57610fbe903690600401610f70565b610ff77f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166108da30821415611f44565b610fff61361a565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611033575061092d90614717565b6040516352d1902d60e01b8152906020826004816001600160a01b0387165afa5f92816110a0575b5061107d5760405162461bcd60e51b8152806110796004820161373f565b0390fd5b61092d9261109b5f5160206156f55f395f51905f52600194146136e1565b614632565b6110c391935060203d6020116110ca575b6110bb8183610cf6565b8101906136d2565b915f61105b565b503d6110b1565b3461023c575f36600319011261023c577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003611129576040515f5160206156f55f395f51905f528152602090f35b60405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608490fd5b3461023c57602036600319011261023c576004355f5260fd602052602060ff60405f2054166040519015158152f35b3461023c575f36600319011261023c5760206111e7600260ff60c95460081c161490565b6040519015158152f35b3461023c576111ff3661071f565b909161120961361a565b5f5b82811061121457005b600190825f5260ff60205260ff61123360405f206107b684888a611eda565b54166112aa57825f5260ff60205261126361125660405f206107b684888a611eda565b805460ff19166001179055565b827f775b5995b6d311d1ac0f46050a5a41564043b346e952189284ec57bd4c0d58dd611290838789611eda565b906112a060405192839283611f33565b0390a25b0161120b565b6112a4565b3461023c575f36600319011261023c576112c761361a565b606580546001600160a01b03199081169091556033805491821690555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461023c57602036600319011261023c576004356001600160401b03811161023c5761134f6113496020923690600401610a1f565b906138b6565b506040519015158152f35b3461023c575f36600319011261023c57606554336001600160a01b03909116036113875761092d33613863565b60405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608490fd5b3461023c575f36600319011261023c576113f661361a565b7fcafd71daf69ac558b30d115a7b5a9751259ac2352764cdf5b7038c74dc43ccb4602060fc5460ff60a01b60ff8260a01c161560a01b169060ff60a01b1916178060fc5560ff6040519160a01c1615158152a1005b3461023c575f36600319011261023c57611476611470600260ff60c95460081c161490565b1561384d565b61020060c95461ff0019161760c9557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a161092d61361a565b3461023c575f36600319011261023c575f5160206156f55f395f51905f52546040516001600160a01b039091168152602090f35b3461023c575f36600319011261023c576033546040516001600160a01b039091168152602090f35b3461023c575f36600319011261023c5760c0610101546101025460801b61010354906040519263ffffffff60e01b8160e01b16845263ffffffff60e01b81861b16602085015261ffff8160401c1660408501526001600160801b03199060301b1660608401526001600160801b031916608083015260a0820152f35b6020906115a29260405193848093610dc5565b9081520301902090565b3461023c57604036600319011261023c576004356024356001600160401b03811161023c57611600602061041e936115ea60ff943690600401610f70565b905f5283825260405f2060405193848093610dc5565b90815203019020546040519116151581529081906020820190565b3461023c57604036600319011261023c576004357fa8796d5584281f38b5f5c7f2ff1ee978acc17db51930ab666a66712c2d9f93ac602060243561165e81610934565b61166661361a565b835f5260fe82526109a98160405f209060ff801983541691151516179055565b3461023c575f36600319011261023c576065546040516001600160a01b039091168152602090f35b3461023c57602036600319011261023c576116c76105d9565b6116cf61361a565b606580546001600160a01b0319166001600160a01b039283169081179091556033549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b35906001600160f01b03198216820361023c57565b6001600160e01b031981160361023c57565b3590610d278261172f565b6001600160801b031981160361023c57565b3590610d278261174c565b35906001600160601b03198216820361023c57565b359063ffffffff198216820361023c57565b61ffff81160361023c57565b3590610d2782611790565b9190916101808184031261023c576117bd610d17565b926117c78261175e565b84526117d560208301611741565b60208501526117e66040830161177e565b60408501526117f76060830161175e565b60608501526080820135608085015260a082013560a085015260c082013560c085015260e08201356001600160401b03811161023c5781611839918401610f70565b60e085015261184b610100830161179c565b61010085015261185e610120830161179c565b6101208501526101408201356001600160401b03811161023c5781611884918401610f70565b6101408501526101608201356001600160401b03811161023c576118a89201610f70565b610160830152565b919060408382031261023c57604051906118c982610c89565b819380356118d681611790565b83526020810135916001600160401b03831161023c576020926118f99201610f70565b910152565b919060608382031261023c5760405161191681610c53565b8093803561192381611790565b8252602081013563ffffffff8116810361023c5760208301526040810135906001600160401b03821161023c57019180601f8401121561023c576040519261196c606085610cf6565b60608101908483831161023c5781905b83821061198e57505050505060400152565b81356001600160401b03811161023c576020916119ae8784938701610f70565b81520191019061197c565b91909160c08184031261023c576119ce610d29565b9281356001600160401b03811161023c57816119eb918401610f70565b845260208201356001600160401b03811161023c5781611a0c918401610f70565b602085015260408201356001600160401b03811161023c5781611a309184016117a7565b604085015260608201356001600160401b03811161023c5781611a54918401610f70565b606085015260808201356001600160401b03811161023c5781611a789184016118b0565b608085015260a08201356001600160401b03811161023c57611a9a92016118fe565b60a0830152565b356102e681611790565b356102e68161174c565b903590601e198136030182121561023c57018035906001600160401b03821161023c57602001918160061b3603831361023c57565b634e487b7160e01b5f52601160045260245ffd5b600181901b91906001600160ff1b03811603611b1657565b611aea565b81810292918115918404141715611b1657565b6002111561023c57565b634e487b7160e01b5f52602160045260245ffd5b60021115611b5657565b611b38565b600160209161ffff8435611b6e81611790565b1661ffff1982541617815501910135611b8681611b2e565b611b8f81611b4c565b60ff80198354169116179055565b600160401b821161092f57610104548261010455808310611c0d575b506101045f527f4c0be60200faa20559308cb7b5a1bb3255c16cb1cab91f525b5ae7a03d02fabe5f915b838310611bf05750505050565b6002604082611c0160019486611b5b565b01920192019190611be3565b6001600160ff1b0381168103611b16576001600160ff1b0383168303611b16576101045f5260205f209060011b8101908360011b015b818110611c505750611bb9565b5f8082556001820155600201611c43565b9035601e198236030181121561023c5701602081359101916001600160401b03821161023c578160061b3603831361023c57565b916020908281520191905f5b818110611cae5750505090565b90919260408060019261ffff8735611cc581611790565b1681526020870135611cd681611b2e565b611cdf81611b4c565b6020820152019401929101611ca1565b610100611da06102e693602084528035611d088161172f565b63ffffffff60e01b1660208501526020810135611d248161172f565b63ffffffff60e01b166040850152611d4c611d416040830161179c565b61ffff166060860152565b611d6c611d5b6060830161175e565b6001600160801b0319166080860152565b611d8c611d7b6080830161175e565b6001600160801b03191660a0860152565b60a081013560c085015260c0810190611c61565b91909260e0808201520191611c95565b15611db757565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b611e2c60ff5f5460081c16611e2781613672565b613672565b6001600160a01b038116611e8b5750611e4433613863565b61010060c95461ff0019161760c95560018060a01b03166001600160601b0360a01b60fb54161760fb5560018060a01b03166001600160601b0360a01b60fc54161760fc55565b611e4490613863565b634e487b7160e01b5f52603260045260245ffd5b903590601e198136030182121561023c57018035906001600160401b03821161023c5760200191813603831361023c57565b90821015611ef557611ef19160051b810190611ea8565b9091565b611e94565b6020919283604051948593843782019081520301902090565b908060209392818452848401375f828201840152601f01601f1916010190565b9160206102e6938181520191611f13565b15611f4b57565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b15611fac57565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b6163746976652070726f787960a01b6064820152608490fd5b9061201082610d74565b61201d6040519182610cf6565b828152809261202e601f1991610d74565b0190602036910137565b818110612043575050565b5f8155600101612038565b9190601f811161205d57505050565b610d27925f5260205f20906020601f840160051c83019310612087575b601f0160051c0190612038565b909150819061207a565b9092916001600160401b03811161092f576120b6816120b08454610df5565b8461204e565b5f601f82116001146120e85781906120e49394955f92610b955750508160011b915f199060031b1c19161790565b9055565b601f198216946120fb845f5260205f2090565b915f5b87811061213557508360019596971061211c575b505050811b019055565b01355f19600384901b60f8161c191690555f8080612112565b909260206001819286860135815501940191016120fe565b903590601e198136030182121561023c57018035906001600160401b03821161023c57602001918160051b3603831361023c57565b903590605e198136030182121561023c570190565b80545f8255806121a5575050565b610d27915f52601f60205f20910160051c810190612038565b90600160401b811161092f5781548183558082106121db57505050565b610d27925f52601f60205f20918180850160051c8401941680612205575b500160051c0190612038565b5f198501908154905f199060200360031b1c1690555f6121f9565b60ff81160361023c57565b356102e681612220565b6008111561023c57565b60081115611b5657565b356102e681612235565b906008811015611b565760ff80198354169116179055565b81358155600181019291612282602082018261214d565b906001600160401b03821161092f576122a99061229f83886121be565b955f5260205f2090565b8160051c915f5b83811061233c5750601f1981169003806122e3575b505050610d279293506122dc604060029201612249565b9101612253565b955f965f5b81811061230857505050019390935590918291906122dc604060026122c5565b90919760206123326001928461231d8d61222b565b919060ff809160031b9316831b921b19161790565b99019291016122e8565b5f5f5b602081106123545750838201556001016122b0565b989060206123686001928c61231d8661222b565b9201990161233f565b600160401b831161092f5780548382558084106123d1575b509061239981925f5260205f2090565b905f925b8484106123ab575050505050565b60036020826123c56123bf60019587612182565b8761226b565b0193019301929161239d565b80600302906003820403611b165783600302600381048503611b1657825f5260205f2091820191015b8181106124075750612389565b805f6003925561241960018201612197565b5f6002820155016123fa565b81604051928392833781015f815203902090565b9035601e198236030181121561023c5701602081359101916001600160401b03821161023c57813603831361023c57565b9035601e198236030181121561023c5701602081359101916001600160401b03821161023c578160051b3603831361023c57565b602081526124f06124e56124c66124b58580612439565b606060208701526080860191611f13565b6124d36020860186612439565b858303601f1901604087015290611f13565b92604081019061246a565b90916060601f19828603019101528083526020830160208260051b85010193835f91605e1982360301905b85841061252c575050505050505090565b90919293949596601f1982820301865287358381121561023c5784019060608101918035825261255f602082018261246a565b606060208501529384905260808301935f905b8082106125ac57505050604001359061258a82612235565b6008821015611b5657604001529660209081019695019360010192919061251b565b90919460208060019260ff89356125c281612220565b168152019601920190612572565b604051906125dd82610c53565b60606040838281528260208201520152565b6001600160401b03811161092f5760051b60200190565b6040519061261382610ca4565b815f81525f60208201526060604082015260608082015260606080820152606060a08201525f60c082015260e06040519161264d83610c53565b606083526060602084015260405161266481610cc0565b60608152606060208201525f604082015260608082015260408401520152565b604051608091906126958382610cf6565b6003815291601f1901825f5b8281106126ad57505050565b6020906126b8612606565b828285010152016126a1565b906003811015611ef55760051b0190565b5190610d2782610934565b81601f8201121561023c576020815191016126fa82610d74565b926127086040519485610cf6565b8284528282011161023c57815f926020928386015e8301015290565b9080601f8301121561023c57815161273b816125ef565b926127496040519485610cf6565b81845260208085019260051b82010192831161023c57602001905b8282106127715750505090565b8151815260209182019101612764565b919060608382031261023c576040519061279a82610c53565b819380516001600160401b03811161023c57826127b89183016126e0565b835260208101516001600160401b03811161023c57826127d99183016126e0565b60208401526040810151906001600160401b03821161023c57019160808383031261023c576040519261280b84610cc0565b80516001600160401b03811161023c57836128279183016126e0565b845260208101516001600160401b03811161023c57836128489183016126e0565b6020850152604081015160408501526060810151926001600160401b03841161023c576040936128789201612724565b60608401520152565b919060408382031261023c57825161289881610934565b926020810151906001600160401b03821161023c57016101008183031261023c576128c1610d38565b91815183526020820151602084015260408201516001600160401b03811161023c57816128ef9184016126e0565b604084015260608201516001600160401b03811161023c57816129139184016126e0565b606084015260808201516001600160401b03811161023c57816129379184016126e0565b608084015260a08201516001600160401b03811161023c578161295b9184016126e0565b60a084015261296c60c083016126d5565b60c084015260e08201516001600160401b03811161023c5761298e9201612781565b60e082015290565b906129ae6020919493946040845260408401906102a9565b931515910152565b6040513d5f823e3d90fd5b805115611ef55760200190565b805160011015611ef55760400190565b805160021015611ef55760600190565b8051821015611ef55760209160051b010190565b6008821015611b565752565b90604051612a1b81610c53565b60028193612a2881610e2d565b8352612a3660018201610e2d565b60208401520190815491612a49836125ef565b92612a576040519485610cf6565b80845260208401915f5260205f20915f905b828210612a7a575050505060400152565b604051612a8681610c53565b84548152604051600186018054808352612aa760208401925f5260205f2090565b905f915b81601f840110612e8c5784600197946003979460209794612bce945491818110612e7b575b818110612e66575b818110612e51575b818110612e3c575b818110612e29575b818110612e14575b818110612dff575b818110612dea575b818110612dd5575b818110612dc0575b818110612dab575b818110612d96575b818110612d81575b818110612d6c575b818110612d57575b818110612d42575b818110612d2d575b818110612d18575b818110612d03575b818110612cee575b818110612cd9575b818110612cc4575b818110612caf575b818110612c9a575b818110612c85575b818110612c70575b818110612c5b575b818110612c46575b818110612c31575b818110612c1c575b818110612c07575b10612bfa575b500382610cf6565b83820152612bec612be360028a015460ff1690565b60408301612a02565b815201940191019092612a69565b60f81c815286015f612bc6565b60ff60f084901c168452928901928b01612bc0565b60ff60e884901c168452928901928b01612bb8565b60ff60e084901c168452928901928b01612bb0565b60ff60d884901c168452928901928b01612ba8565b60ff60d084901c168452928901928b01612ba0565b60ff60c884901c168452928901928b01612b98565b60ff60c084901c168452928901928b01612b90565b60ff60b884901c168452928901928b01612b88565b60ff60b084901c168452928901928b01612b80565b60ff60a884901c168452928901928b01612b78565b60ff60a084901c168452928901928b01612b70565b60ff609884901c168452928901928b01612b68565b60ff609084901c168452928901928b01612b60565b60ff608884901c168452928901928b01612b58565b60ff608084901c168452928901928b01612b50565b60ff607884901c168452928901928b01612b48565b60ff607084901c168452928901928b01612b40565b60ff606884901c168452928901928b01612b38565b60ff606084901c168452928901928b01612b30565b60ff605884901c168452928901928b01612b28565b60ff605084901c168452928901928b01612b20565b60ff604884901c168452928901928b01612b18565b60ff604084901c168452928901928b01612b10565b60ff603884901c168452928901928b01612b08565b60ff603084901c168452928901928b01612b00565b60ff602884901c168452928901928b01612af8565b60ff838b1c168452928901928b01612af0565b60ff601884901c168452928901928b01612ae8565b60ff601084901c168452928901928b01612ae0565b60ff600884901c168452928901928b01612ad8565b60ff83168452928901928b01612ad0565b92600161040060209261304e8754612ea98360ff831660ff169052565b600881901c60ff1683870152601081901c60ff166040840152601881901c60ff16606084015280861c60ff166080840152602881901c60ff1660a0840152603081901c60ff1660c0840152603881901c60ff1660e0840152604081901c60ff16610100840152604881901c60ff16610120840152605081901c60ff16610140840152605881901c60ff16610160840152606081901c60ff16610180840152606881901c60ff166101a0840152607081901c60ff166101c0840152607881901c60ff166101e0840152608081901c60ff16610200840152608881901c60ff16610220840152609081901c60ff16610240840152609881901c60ff1661026084015260a081901c60ff1661028084015260a881901c60ff166102a084015260b081901c60ff166102c084015260b881901c60ff166102e084015260c081901c60ff1661030084015260c881901c60ff1661032084015260d081901c60ff1661034084015260d881901c60ff1661036084015260e081901c60ff1661038084015260e881901c60ff166103a084015260f081901c60ff166103c084015260f81c6103e0830152565b019401920191612aab565b80516001600160801b03191682526102e6916020828101516001600160e01b0319169082015260408281015163ffffffff1916908201526060828101516001600160801b031916908201526080820151608082015260a082015160a082015260c082015160c08201526101606131156130e360e085015161018060e08601526101808501906102a9565b6101008581015161ffff16908501526101208581015161ffff16908501526101408501518482036101408601526102a9565b920151906101608184039101526102a9565b906040606082019261ffff815116835263ffffffff6020820151166020840152015191606060408301529060c0810192915f905b6003821061316a575050505090565b90919293602080613187600193605f1988820301865288516102a9565b96019201920190929161315b565b6102e69160a06132196131f06131de6131cc6131ba875160c0885260c08801906102a9565b602088015187820360208901526102a9565b60408701518682036040880152613059565b606086015185820360608701526102a9565b604060206080870151868403608088015261ffff815116845201519181602082015201906102a9565b9201519060a0818403910152613127565b906102e691602081526132bb60c0835161ffff60f01b815116602085015261ffff60f01b602082015116604085015263ffffffff60e01b604082015116606085015261ffff60f01b606082015116608085015261ffff60f01b60808201511660a08501526132a860a0820151838601906001600160801b0319169052565b01516001600160601b03191660e0830152565b60406132d96020840151610120610100850152610140840190613059565b92015190610120601f1982850301910152613195565b9081526008821015611b565760219160f81b60208201520190565b6040516001600160f81b0319602082015260018152919061332c602184610cf6565b61333581613ad4565b969391509150156136115760fc549460a086901c60ff166135af575b6040840191613364604084510151613eee565b90156135065780613376600192611b4c565b146135a4576133836125d0565b5061338c612684565b965f906133a9906001600160a01b03165b6001600160a01b031690565b905b600381106135125750506020604060e06133c48a6129c1565b510151015101516133fb61065f6133e26133dd84610dd7565b612a0e565b9260208401516020815191012090602081519101201490565b6135065761342d61065f604060e06134128c6129c1565b51015101515183516020815191012090602081519101201490565b613506576134489060e06134408a6129c1565b510151614085565b9790156135065761345b61065f826141b5565b613506579161348293916040608061347561065f966129c1565b5101519351015192614464565b6134fe57505f6134bc6134a26134b060209460405192839187830161322a565b03601f198101835282610cf6565b60405191828092610dc5565b039060025afa156134f9576134f5826134f05f516134e2604051968792602084016132ef565b03601f198101865285610cf6565b6145b7565b9190565b6129b6565b9250505f9190565b505050509250505f9190565b6135465f61352883604060a089015101516126c4565b516040518093819263c1c1d5c160e01b835286159060048401612996565b0381865afa80156134f9575f915f91613580575b50613565838c6129ee565b5215613573576001016133ab565b50505050509250505f9190565b905061359e91503d805f833e6135968183610cf6565b810190612881565b5f61355a565b5050509250505f9190565b602084016135ee6135d560c06135dc6135d56080865101515f5260fd60205260405f2090565b5460ff1690565b935101515f5260fe60205260405f2090565b9015908115613608575b50156133515750509250505f9190565b9050155f6135f8565b509250505f9190565b6033546001600160a01b0316330361362e57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b1561367957565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b9081602091031261023c575190565b156136e857565b60405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608490fd5b60809060208152602e60208201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960408201526d6f6e206973206e6f74205555505360901b60608201520190565b906137ba7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1690565b156137c95750610d2790614717565b6040516352d1902d60e01b8152906020826004816001600160a01b0387165afa5f928161382c575b5061380f5760405162461bcd60e51b8152806110796004820161373f565b610d279261109b5f5160206156f55f395f51905f525f94146136e1565b61384691935060203d6020116110ca576110bb8183610cf6565b915f6137f1565b1561385457565b63bae6e2a960e01b5f5260045ffd5b606580546001600160a01b0319908116909155603380549182166001600160a01b0393841690811790915591167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b6040516001600160f81b031960208201526001815292916138f9916138f4906138e0602187610cf6565b60fc546001600160a01b0316923691610d8f565b6147ae565b901561390a57611ef191925061330a565b505f9190565b6040519061391d82610c6e565b5f60c0838281528260208201528260408201528260608201528260808201528260a08201520152565b6040519061018082018281106001600160401b0382111761092f576040526060610160835f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201528260e08201525f6101008201525f610120820152826101408201520152565b604051906139bc82610c89565b60606020835f81520152565b6060906040516139d88382610cf6565b80925f5b8181106139e857505050565b8082602092850152016139dc565b60405190613a0382610c53565b815f81525f602082015260406118f96139c8565b6040519060c082018281106001600160401b0382111761092f57604052816060815260606020820152613a48613946565b6040820152606080820152613a5b6139af565b608082015260a06118f96139f6565b61ffff166103f2019061ffff8211611b1657565b61ffff60029116019061ffff8211611b1657565b61ffff60049116019061ffff8211611b1657565b61ffff16610242019061ffff8211611b1657565b9063ffffffff8091169116019063ffffffff8211611b1657565b90613add613910565b50613ae6613946565b50613aef613a17565b506001916020810151906040810190604082510151606060e08501515114801590613dbc575b8015613dab575b613d9c57606060e0820151511490811591613d8a575b8115613d78575b50613d6a57600561ffff613b5460a0855101515161ffff1690565b1603613d5b57815160408151511490811591613d4a575b8115613d39575b50613d2a5760808251015161ffff6020613b8f8361ffff90511690565b92015151911603613d1b576103fc63ffffffff613be9613bcf613bca613bc5613bc060808951015161ffff90511690565b613a6a565b613a7e565b613a92565b855160a001516020015163ffffffff169061ffff16613aba565b161115613d0c575192613d01613d07613c07865161ffff60f01b1690565b6020870151613ce5906001600160f01b031916916134a2613c3260408b015163ffffffff60e01b1690565b60608b01518b906001600160f01b03191660808201516001600160f01b03191690613c7d60c0613c6d60a08601516001600160801b03191690565b9401516001600160601b03191690565b6040516001600160f01b0319978816602082015298871660228a01526001600160e01b031990941660248901528516602888015293909316602a8601526001600160801b0319909216602c8501526001600160601b0319909116603c84015282906050820190565b6134a2613cf187614912565b6040519485936020850190610dc5565b90610dc5565b915190565b631350008b60e31b5f5260045ffd5b630c6543ad60e01b5f5260045ffd5b6346ac673f60e01b5f5260045ffd5b60409150606001515114155f613b72565b602081015151604014159150613b6b565b63213d071160e21b5f5260045ffd5b623dc25960e41b5f5260045ffd5b6040915061016001515114155f613b39565b61014081015151603c14159150613b32565b633c20ffcf60e11b5f5260045ffd5b506040610160850151511415613b1c565b50603c610140850151511415613b15565b908154613dd9816125ef565b92613de76040519485610cf6565b81845260208401905f5260205f205f915b838310613e055750505050565b60026020600192604051613e1881610c89565b604051613e2481610cdb565b61ffff8754168152815260ff8587015416613e3e81611b4c565b83820152815201920192019190613df8565b60405190613e5d82610c6e565b6101015460e081901b6001600160e01b0319908116845260c082901b166020840152604081811c61ffff16908401528290613eb790613ea69060301b6001600160801b03191690565b6001600160801b0319166060830152565b613ed8613ec76101025460801b90565b6001600160801b0319166080830152565b6101035460a082015260c06118f9610104613dcd565b905f91613ef9613e50565b60208201516001600160e01b03191660208201516001600160e01b03191616613f39613f2c835163ffffffff60e01b1690565b6001600160e01b03191690565b60608401516001600160e01b03199092161492906001600160801b03191660808301516001600160801b03191616613f8c613f7f60608501516001600160801b03191690565b6001600160801b03191690565b906001600160801b0319161460c082015160a08401511490613fb461010084015161ffff1690565b61ffff613fd0613fc9604088015161ffff1690565b61ffff1690565b9116149260c05f950190815151915f5b838110614029575b5050505084614021575b5083614019575b5082614011575b508161400b57509190565b90509190565b91505f614000565b92505f613ff9565b93505f613ff2565b6140348183516129ee565b5180515161ffff1661ffff614052613fc961012088015161ffff1690565b911611156140635750600101613fe0565b97505050505095506020600193015161407b81611b4c565b955f808080613fe8565b9060400190815151915f5b8381106140a35750505050600190600790565b6140ae8183516129ee565b5160408401516140d060606040830151845111159201516020840151906149da565b8161410a575b506140e45750600101614090565b92505050604091500151906140f88261223f565b6141018261223f565b60068214159190565b90505f6140d6565b5f19810191908211611b1657565b600119810191908211611b1657565b6101b319810191908211611b1657565b9060018201809211611b1657565b9060028201809211611b1657565b9060048201809211611b1657565b9081602091031261023c57516102e681610934565b916141a7906141996102e695936060865260608601906102a9565b9084820360208601526102a9565b9160408184039101526102a9565b805160fb545f928392839283928392916141d7906001600160a01b031661339d565b905b828410614213575b5050505015928361420b575b5082614203575b50816141fe575090565b905090565b91505f6141f4565b92505f6141ed565b9091929496614220612606565b5061422a84614112565b8603614363575061423b85826129ee565b51945b61424881836129ee565b51514211978861434a575b88156143435750606061426682846129ee565b510151956020608060a061427a85876129ee565b5101519201918251986142a16040519a8b9384936326995c1560e21b85526004850161417e565b0381875afa9687156134f9575f97614313575b50861561430d576142eb7f89f72d7c488e5b53a77c23ebcb36970ef7eb5bcf6658e9b8292cfbe4703a847391516020815191012090565b146142fb576001019291906141d9565b5050505091506001915f8080806141e1565b506141e1565b61433591975060203d811161433c575b61432d8183610cf6565b810190614169565b955f6142b4565b503d614323565b95506141e1565b9750602061435882846129ee565b510151421097614253565b93946143776143718261413f565b836129ee565b519561438285614120565b82036143e3575060015f5260ff6020526143ce6135d57ff806280aa4dfe145596c627f696302876be30d4ea721e7e2b62aecde7954710a5b60406143c685876129ee565b51015161158f565b94855b6143db575061423e565b9795506141e1565b946143fb60c06143f384866129ee565b510151151590565b614406575b856143d1565b5f805260ff602052945061443c6135d57f03d616f3758432b4d7452e2e9011612152589bfc903ce751686613c478b2af5f6143ba565b94614400565b602081519101519060208110614456575090565b5f199060200360031b1b1690565b9261447961016061447e929493940151614a3d565b614442565b602082019060205f6144ab613d016134b086516134a28660808b0151015160405194859389850190610dc5565b039060025afa156134f9575f51036145af576144ca6040830151614912565b60fb549092906020906144e5906001600160a01b031661339d565b60608301516040516326995c1560e21b81529791958892839261450b926004850161417e565b0381865afa9485156134f9575f95614583575b505190516040516326995c1560e21b815293602093859390928492839261454992916004850161417e565b03915afa9081156134f9575f916145645750816141fe575090565b61457d915060203d60201161433c5761432d8183610cf6565b5f6141f4565b602093919550916145a46145499593853d871161433c5761432d8183610cf6565b95919350919361451e565b505050505f90565b6008811015611b5657801590811561461d575b8115614608575b81156145f3575b81156145e2575090565b600591506145ef8161223f565b1490565b90506145fe8161223f565b60048114906145d8565b90506146138161223f565b60028114906145d1565b90506146288161223f565b60018114906145ca565b9161463c83614717565b6001600160a01b0383167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28151159081159161470f575b5061467f575050565b614704915f8060405193614694606086610cf6565b602785527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c6020860152660819985a5b195960ca1b6040860152602081519101845af43d15614707573d916146e883610d74565b926146f66040519485610cf6565b83523d5f602085013e615522565b50565b606091615522565b90505f614676565b803b156147535760018060a01b03166001600160601b0360a01b5f5160206156f55f395f51905f525416175f5160206156f55f395f51905f5255565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b604051906147bb82610c53565b6147c3613910565b82526147cd613946565b60208301526147da613a17565b6040830152816103fc8251111561486c57506147fd6147f882614a6a565b614d97565b9283614809835161412f565b036148805761481f61481a83614a8c565b614f0a565b94901561487657906148346148399284614aa2565b6150a4565b92901561486c575061484d61485291614ac4565b61523f565b61485a610d48565b92835260208301526040820152600191565b93925050505f9190565b505f949293505050565b505f9391925050565b91956148ef956004999560a0956102e69f9e9c9a9499613d019e9a6001600160801b031916875263ffffffff60e01b16601087015263ffffffff191660148601526001600160801b03191660308501526040840152606083015260808201520190610dc5565b6001600160f01b031960f093841b811682529190921b1660028201520190610dc5565b6102e660206134a261492a61010085015161ffff1690565b614941600882901c60ff165b9160081b61ff001690565b1761495261012086015161ffff1690565b614962600882901c60ff16614936565b179461497681516001600160801b03191690565b818501519096906001600160e01b0319169261499a604084015163ffffffff191690565b60608401516001600160801b031916608085015160a08601519060c08701519260e0880151946101606101408a0151990151996040519e8f9d8e01614889565b906010825114801590614a31575b614a2b575f5b601081106149fe57505050600190565b614a0881846129ee565b5160ff614a1583856129ee565b511611614a24576001016149ee565b5050505f90565b50505f90565b506010815114156149e8565b8051602011614a5b57602080614a5281612006565b92018183015e90565b6343733a0960e11b5f5260045ffd5b80516101b411614a5b5760046101d0614a8282612006565b9201602083015e90565b8051603011614a5b5760306020614a8282612006565b90806101b401806101b411611b1657825110614a5b576101d4614a8282612006565b80516101b011614a5b576101806050614a8282612006565b8051600211614a5b5760026020614a8282612006565b8051600411614a5b5760026022614a8282612006565b8051600811614a5b5760046024614a8282612006565b8051601c11614a5b576010602c614a8282612006565b8051600a11614a5b5760026028614a8282612006565b8051600c11614a5b576002602a614a8282612006565b8051603011614a5b576014603c614a8282612006565b805161024211614a5b576002610260614a8282612006565b9080610242018061024211611b1657825110614a5b57610262614a8282612006565b9060028101808211611b1657825110614a5b576020600291614bd183612006565b930101602083015e90565b9060048101808211611b1657825110614a5b576020600491614bd183612006565b8051604011614a5b5760406020614a8282612006565b8051608011614a5b5760406060614a8282612006565b805161020011614a5b5761018060a0614a8282612006565b805161024011614a5b576040610220614a8282612006565b8051601011614a5b5760106020614a8282612006565b8051601411614a5b5760046030614a8282612006565b8051603011614a5b57601c6034614a8282612006565b8051604011614a5b5760106050614a8282612006565b8051606011614a5b5760206060614a5282612006565b8051608011614a5b5760206080614a5282612006565b805160a011614a5b57602060a0614a5282612006565b805161010011614a5b57606060c0614a8282612006565b805161010211614a5b576002610120614a8282612006565b805161010411614a5b576002610122614a8282612006565b805161014011614a5b57603c610124614a8282612006565b805161018011614a5b576040610160614a8282612006565b9190818101808211611b1657835110614a5b57602090614bd183612006565b603f8111611b165760100a90565b905f9180515f915b818310614dab57505050565b9091938151851015611ef5576020858301015160f81c614dfb614de6600f8360041c9316614de0614ddb8a611afe565b614d89565b90611b1b565b91614de0614ddb614df68a611afe565b61413f565b8101809111611b16578101809111611b1657936001019190614d9f565b80516020909101516001600160f01b0319811692919060028210614e3a575050565b6001600160f01b031960029290920360031b82901b16169150565b80516020909101516001600160e01b0319811692919060048210614e77575050565b6001600160e01b031960049290920360031b82901b16169150565b9060208251920151916001600160801b031983169260108210614eb3575050565b6001600160801b031960109290920360031b82901b16169150565b9060208251920151916001600160601b031983169260148210614eef575050565b6001600160601b031960149290920360031b82901b16169150565b614f12613910565b90614f24614f1f82614adc565b614e18565b9160fd60f81b6001600160f01b031984160161509b57614f46614f1f83614af2565b91607f60f91b6001600160f01b031984160161509157614f6d614f6882614b08565b614e55565b6001600160e01b0319811661508657614f8d614f8883614b1e565b614e92565b926f6c658dcc0863b3566bf5f24c6a80f9f960801b6001600160801b031985160161507a575091615053826150426150759695615031614fd2614f1f61506498614b34565b91615020614ff3614fee614fe8614f1f89614b4a565b97614b60565b614ece565b9961500f614fff610d57565b6001600160f01b0319909e168e52565b6001600160f01b03191660208d0152565b6001600160e01b03191660408b0152565b6001600160f01b0319166060890152565b6001600160f01b0319166080870152565b6001600160801b03191660a0850152565b6001600160601b03191660c0830152565b600191565b959450505050505f9190565b5050929150505f9190565b50929150505f9190565b929150505f9190565b906150ad613a17565b916150b66139af565b906150d16150c9613fc96147f884614b76565b61ffff168352565b6150ea61ffff6150e3845161ffff1690565b1682614b8e565b6020830152615106613fc9615101845161ffff1690565b613aa6565b9261510f6139f6565b9361512b615123613fc96147f88487614bb0565b61ffff168652565b61ffff61513a865161ffff1690565b16600181109081156151fe575b506151f4576151e092916151a76151606151ac9361414d565b6151a06151796151956151826151796147f8868b614bdc565b63ffffffff1690565b63ffffffff1660208c019081529361415b565b925163ffffffff1690565b9085614d6a565b615424565b60408501526151ba81614bfd565b85526151c581614c13565b60208601526151d661484d82614c29565b6040860152614c41565b6060840152608083015260a0820152600191565b505f959350505050565b60059150115f615147565b90602082519201519163ffffffff19831692601c8210615227575050565b63ffffffff19601c9290920360031b82901b16169150565b906118a861524b613946565b9261526961525b614f8883614c59565b6001600160801b0319168552565b615289615278614f6883614c6f565b6001600160e01b0319166020860152565b6152ab61529d61529883614c85565b615209565b63ffffffff19166040860152565b6152cb6152ba614f8883614c9b565b6001600160801b0319166060860152565b6152d761447982614cb1565b60808501526152e861447982614cc7565b60a08501526152f961447982614cdd565b60c085015261530781614cf3565b60e085015261532a61531e613fc96147f884614d0a565b61ffff16610100860152565b61534861533c613fc96147f884614d22565b61ffff16610120860152565b61535181614d3a565b610140850152614d52565b919060408382031261023c57825161537381610934565b926020810151906001600160401b03821161023c57019080601f8301121561023c5781516153a0816125ef565b926153ae6040519485610cf6565b81845260208085019260051b8201019183831161023c5760208201905b8382106153da57505050505090565b81516001600160401b03811161023c576020916153fc878480948801016126e0565b8152019101906153cb565b9190602061541f6003926040865260408601906102a9565b930152565b5f9061544e926154326139c8565b506040518080958194635b732b7d60e11b835260048301615407565b03916001600160a01b03165afa9081156134f9575f905f926154fd575b50156154ee57615479612684565b505f5b600381106154bc57506154b36154926060610d66565b9161549c816129c1565b5183526154a8816129ce565b5160208401526129de565b51604082015290565b806154d26154cc600193856129ee565b516155bb565b6154dc82856129ee565b526154e781846129ee565b500161547c565b636237e47b60e11b5f5260045ffd5b905061551b91503d805f833e6155138183610cf6565b81019061535c565b905f61546b565b919290156155845750815115615536575090565b3b1561553f5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156155975750805190602001fd5b60405162461bcd60e51b8152602060048201529081906110799060248301906102a9565b906060918051806155ca575050565b90925060038160021c0290600381169081156156b95750015f19015b6040519281845260208401918401916003600460208501935f5160206156d55f395f51905f52605b527804080c1014181c2024282c3034383c4044484c5054585c6064603b526ef8fcf800fcd0d4d8dce0e4e8ecf0f4601a525b0191825160ff81165160061c81601e1a515f5160206156d55f395f51905f52161760061c81601d1a515f5160206156d55f395f51905f52161760061c90601c1a515f5160206156d55f395f51905f52161781520190828210156156a857600390600490615640565b505060405f9201604052525f606052565b613d3d91508401511860ff81161590601e1a150190036155e656fefc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca264697066735822122055b677081c87cfe8bb34853c524afbd78964980187cdabb3b9a5255137385df164736f6c634300081e0033
Deployed ByteCode
0x60806040526004361015610011575f80fd5b5f3560e01c806301d711f41461021457806304f3bcec1461020f5780630570e1fc1461020a578063089a168f146102055780630d23d71b14610200578063123ac29e146101fb578063184b9559146101f65780631f3be096146101f15780633075db56146101ec57806332f555ec146101e75780633659cfe6146101e25780633a343014146101dd5780633f4ba83a146101d85780634bc7eea4146101d35780634c0977a9146101ce5780634f1ef286146101c957806352d1902d146101c457806354e21913146101bf5780635c975abb146101ba578063610de480146101b5578063715018a6146101b0578063769d87e7146101ab57806379ba5097146101a657806383801580146101a15780638456cb591461019c5780638abf6077146101975780638da5cb5b14610192578063b684252f1461018d578063cf12f55514610188578063e2e2829414610183578063e30c39781461017e5763f2fde38b14610179575f80fd5b6116ae565b611686565b61161b565b6115ac565b611513565b6114eb565b6114b7565b61144b565b6113de565b61135a565b611314565b6112af565b6111f1565b6111c3565b611194565b6110d1565b610f8b565b610ef0565b610a4c565b6109b4565b61093e565b610888565b610859565b610836565b610774565b61061b565b61044a565b610422565b6102e9565b610284565b610240565b3461023c575f36600319011261023c5760fc546040516001600160a01b039091168152602090f35b5f80fd5b3461023c575f36600319011261023c576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461023c575f36600319011261023c57602060ff60fc5460a01c166040519015158152f35b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b6040906102e693921515815281602082015201906102a9565b90565b3461023c57602036600319011261023c576004356001600160401b03811161023c5760031981360301610120811261023c5760e06040519161032a83610c53565b1261023c5760405161033b81610c6e565b6103478360040161171a565b81526103556024840161171a565b602082015260448301356103688161172f565b60408201526103796064840161171a565b606082015261038a6084840161171a565b608082015260a483013561039d8161174c565b60a08201526103ae60c48401611769565b60c0820152815260e48201356001600160401b03811161023c576103d890600436918501016117a7565b60208201526101048201356001600160401b03811161023c5761040e92600461040492369201016119b9565b604082015261330a565b9061041e604051928392836102cd565b0390f35b3461023c575f36600319011261023c5760fb546040516001600160a01b039091168152602090f35b3461023c57602036600319011261023c576004356001600160401b03811161023c57806004019060e0600319823603011261023c577f8867fcb26463d2f77f8c8f24316221d64d8b4821bf4dea1b4c9b83d4ba271c45916105c86105c260c46105d4946104b561361a565b84356104c08161172f565b60e01c63ffffffff196101015416176101015561050b60248201356104e48161172f565b67ffffffff0000000080610101549260c01c16169067ffffffff0000000019161761010155565b61053961051a60448301611aa1565b61ffff60401b610101549160401b169061ffff60401b19161761010155565b61058661054860648301611aab565b61010180546fffffffffffffffffffffffffffffffff60501b191660309290921c6fffffffffffffffffffffffffffffffff60501b16919091179055565b6105ad61059560848301611aab565b60801c6001600160801b031961010254161761010255565b6105bb60a482013561010355565b0183611ab5565b90611b9d565b60405191829182611cef565b0390a1005b600435906001600160a01b038216820361023c57565b602435906001600160a01b038216820361023c57565b604435906001600160a01b038216820361023c57565b3461023c57606036600319011261023c576106346105d9565b61069361063f6105ef565b610647610605565b905f549361067961066361065f8760ff9060081c1690565b1590565b80968197610711575b81156106f1575b50611db0565b8461068a600160ff195f5416175f55565b6106da57611e13565b61069957005b6106a75f5461ff0019165f55565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989080602081016105d4565b6106ec6101005f5461ff001916175f55565b611e13565b303b15915081610703575b505f610673565b60ff1660011490505f6106fc565b600160ff821610915061066c565b604060031982011261023c57600435916024356001600160401b03811161023c578260238201121561023c578060040135926001600160401b03841161023c5760248460051b8301011161023c576024019190565b3461023c576107823661071f565b909161078c61361a565b5f5b82811061079757005b600190825f5260ff60205260ff6107bc60405f206107b684888a611eda565b90611efa565b54161561083157825f5260ff6020526107ea6107e060405f206107b684888a611eda565b805460ff19169055565b827fee365795c95effb059e7128967d8e0dce7b2eaaf750bb4c422df5411fb8aedfd610817838789611eda565b9061082760405192839283611f33565b0390a25b0161078e565b61082b565b3461023c575f36600319011261023c576020600260ff60c9541614604051908152f35b3461023c57602036600319011261023c576004355f5260fe602052602060ff60405f2054166040519015158152f35b3461023c57602036600319011261023c576108a16105d9565b6108f87f0000000000000000000000003b36ba4b3b3a0303001161b53bae0c3acd6ef2126001600160a01b03166108da30821415611f44565b5f5160206156f55f395f51905f52546001600160a01b031614611fa5565b61090061361a565b60405161092d91610912602083610cf6565b5f8252601f196109215f610d74565b0136602084013761378e565b005b610c3f565b8015150361023c57565b3461023c57604036600319011261023c576004357fe9c8da9c89154486636f96dbbf87f6cdf819637dda597383e5b1533b446b51d2602060243561098181610934565b61098961361a565b835f5260fd82526109a98160405f209060ff801983541691151516179055565b6040519015158152a2005b3461023c575f36600319011261023c576109de6109d9600260ff60c95460081c161490565b61384d565b61010060c95461ff0019161760c9557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a161092d61361a565b9181601f8401121561023c578235916001600160401b03831161023c576020838186019501011161023c57565b3461023c57604036600319011261023c576004356001600160401b03811161023c57610a7c903690600401610a1f565b602435916001600160401b03831161023c5782600401926060600319823603011261023c57610aa961361a565b6040518383823760208185810161010081520301902090610aca8580611ea8565b906001600160401b03821161092f57610aed82610ae78654610df5565b8661204e565b5f90601f8311600114610ba057610b8394610b7560447f540fc9dd1a61f44f6860558982bac073b37667cb331897eb59633910cfd038229996610b5187610b909b98610b7e986002985f92610b95575b50508160011b915f199060031b1c19161790565b84555b610b6e610b64602483018e611ea8565b9060018701612091565b018a61214d565b92909101612371565b612425565b926040519182918261249e565b0390a2005b013590505f80610b3d565b601f19831691610bb3865f5260205f2090565b925f5b818110610c27575060447f540fc9dd1a61f44f6860558982bac073b37667cb331897eb59633910cfd038229996600187610b7e97600297610b839c97610b909e9b610b759810610c0e575b505050811b018455610b54565b01355f19600384901b60f8161c191690555f8080610c01565b91936020600181928787013581550195019201610bb6565b634e487b7160e01b5f52604160045260245ffd5b606081019081106001600160401b0382111761092f57604052565b60e081019081106001600160401b0382111761092f57604052565b604081019081106001600160401b0382111761092f57604052565b61010081019081106001600160401b0382111761092f57604052565b608081019081106001600160401b0382111761092f57604052565b602081019081106001600160401b0382111761092f57604052565b90601f801991011681019081106001600160401b0382111761092f57604052565b60405190610d2761018083610cf6565b565b60405190610d2760c083610cf6565b60405190610d2761010083610cf6565b60405190610d27606083610cf6565b60405190610d2760e083610cf6565b90610d276040519283610cf6565b6001600160401b03811161092f57601f01601f191660200190565b929192610d9b82610d74565b91610da96040519384610cf6565b82948184528183011161023c578281602093845f960137010152565b805191908290602001825e015f815290565b6020610de99160405192838092610dc5565b61010081520301902090565b90600182811c92168015610e23575b6020831014610e0f57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610e04565b9060405191825f825492610e4084610df5565b8084529360018116908115610ea95750600114610e65575b50610d2792500383610cf6565b90505f9291925260205f20905f915b818310610e8d575050906020610d27928201015f610e58565b6020919350806001915483858901015201910190918492610e74565b905060209250610d2794915060ff191682840152151560051b8201015f610e58565b9091610ee26102e6936040845260408401906102a9565b9160208184039101526102a9565b3461023c57602036600319011261023c576004356001600160401b03811161023c573660238201121561023c576020610f36610f42923690602481600401359101610d8f565b60405192838092610dc5565b610100815203019020610f606001610f5983610e2d565b9201610e2d565b9061041e60405192839283610ecb565b9080601f8301121561023c578160206102e693359101610d8f565b604036600319011261023c57610f9f6105d9565b6024356001600160401b03811161023c57610fbe903690600401610f70565b610ff77f0000000000000000000000003b36ba4b3b3a0303001161b53bae0c3acd6ef2126001600160a01b03166108da30821415611f44565b610fff61361a565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611033575061092d90614717565b6040516352d1902d60e01b8152906020826004816001600160a01b0387165afa5f92816110a0575b5061107d5760405162461bcd60e51b8152806110796004820161373f565b0390fd5b61092d9261109b5f5160206156f55f395f51905f52600194146136e1565b614632565b6110c391935060203d6020116110ca575b6110bb8183610cf6565b8101906136d2565b915f61105b565b503d6110b1565b3461023c575f36600319011261023c577f0000000000000000000000003b36ba4b3b3a0303001161b53bae0c3acd6ef2126001600160a01b03163003611129576040515f5160206156f55f395f51905f528152602090f35b60405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608490fd5b3461023c57602036600319011261023c576004355f5260fd602052602060ff60405f2054166040519015158152f35b3461023c575f36600319011261023c5760206111e7600260ff60c95460081c161490565b6040519015158152f35b3461023c576111ff3661071f565b909161120961361a565b5f5b82811061121457005b600190825f5260ff60205260ff61123360405f206107b684888a611eda565b54166112aa57825f5260ff60205261126361125660405f206107b684888a611eda565b805460ff19166001179055565b827f775b5995b6d311d1ac0f46050a5a41564043b346e952189284ec57bd4c0d58dd611290838789611eda565b906112a060405192839283611f33565b0390a25b0161120b565b6112a4565b3461023c575f36600319011261023c576112c761361a565b606580546001600160a01b03199081169091556033805491821690555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461023c57602036600319011261023c576004356001600160401b03811161023c5761134f6113496020923690600401610a1f565b906138b6565b506040519015158152f35b3461023c575f36600319011261023c57606554336001600160a01b03909116036113875761092d33613863565b60405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608490fd5b3461023c575f36600319011261023c576113f661361a565b7fcafd71daf69ac558b30d115a7b5a9751259ac2352764cdf5b7038c74dc43ccb4602060fc5460ff60a01b60ff8260a01c161560a01b169060ff60a01b1916178060fc5560ff6040519160a01c1615158152a1005b3461023c575f36600319011261023c57611476611470600260ff60c95460081c161490565b1561384d565b61020060c95461ff0019161760c9557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a161092d61361a565b3461023c575f36600319011261023c575f5160206156f55f395f51905f52546040516001600160a01b039091168152602090f35b3461023c575f36600319011261023c576033546040516001600160a01b039091168152602090f35b3461023c575f36600319011261023c5760c0610101546101025460801b61010354906040519263ffffffff60e01b8160e01b16845263ffffffff60e01b81861b16602085015261ffff8160401c1660408501526001600160801b03199060301b1660608401526001600160801b031916608083015260a0820152f35b6020906115a29260405193848093610dc5565b9081520301902090565b3461023c57604036600319011261023c576004356024356001600160401b03811161023c57611600602061041e936115ea60ff943690600401610f70565b905f5283825260405f2060405193848093610dc5565b90815203019020546040519116151581529081906020820190565b3461023c57604036600319011261023c576004357fa8796d5584281f38b5f5c7f2ff1ee978acc17db51930ab666a66712c2d9f93ac602060243561165e81610934565b61166661361a565b835f5260fe82526109a98160405f209060ff801983541691151516179055565b3461023c575f36600319011261023c576065546040516001600160a01b039091168152602090f35b3461023c57602036600319011261023c576116c76105d9565b6116cf61361a565b606580546001600160a01b0319166001600160a01b039283169081179091556033549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b35906001600160f01b03198216820361023c57565b6001600160e01b031981160361023c57565b3590610d278261172f565b6001600160801b031981160361023c57565b3590610d278261174c565b35906001600160601b03198216820361023c57565b359063ffffffff198216820361023c57565b61ffff81160361023c57565b3590610d2782611790565b9190916101808184031261023c576117bd610d17565b926117c78261175e565b84526117d560208301611741565b60208501526117e66040830161177e565b60408501526117f76060830161175e565b60608501526080820135608085015260a082013560a085015260c082013560c085015260e08201356001600160401b03811161023c5781611839918401610f70565b60e085015261184b610100830161179c565b61010085015261185e610120830161179c565b6101208501526101408201356001600160401b03811161023c5781611884918401610f70565b6101408501526101608201356001600160401b03811161023c576118a89201610f70565b610160830152565b919060408382031261023c57604051906118c982610c89565b819380356118d681611790565b83526020810135916001600160401b03831161023c576020926118f99201610f70565b910152565b919060608382031261023c5760405161191681610c53565b8093803561192381611790565b8252602081013563ffffffff8116810361023c5760208301526040810135906001600160401b03821161023c57019180601f8401121561023c576040519261196c606085610cf6565b60608101908483831161023c5781905b83821061198e57505050505060400152565b81356001600160401b03811161023c576020916119ae8784938701610f70565b81520191019061197c565b91909160c08184031261023c576119ce610d29565b9281356001600160401b03811161023c57816119eb918401610f70565b845260208201356001600160401b03811161023c5781611a0c918401610f70565b602085015260408201356001600160401b03811161023c5781611a309184016117a7565b604085015260608201356001600160401b03811161023c5781611a54918401610f70565b606085015260808201356001600160401b03811161023c5781611a789184016118b0565b608085015260a08201356001600160401b03811161023c57611a9a92016118fe565b60a0830152565b356102e681611790565b356102e68161174c565b903590601e198136030182121561023c57018035906001600160401b03821161023c57602001918160061b3603831361023c57565b634e487b7160e01b5f52601160045260245ffd5b600181901b91906001600160ff1b03811603611b1657565b611aea565b81810292918115918404141715611b1657565b6002111561023c57565b634e487b7160e01b5f52602160045260245ffd5b60021115611b5657565b611b38565b600160209161ffff8435611b6e81611790565b1661ffff1982541617815501910135611b8681611b2e565b611b8f81611b4c565b60ff80198354169116179055565b600160401b821161092f57610104548261010455808310611c0d575b506101045f527f4c0be60200faa20559308cb7b5a1bb3255c16cb1cab91f525b5ae7a03d02fabe5f915b838310611bf05750505050565b6002604082611c0160019486611b5b565b01920192019190611be3565b6001600160ff1b0381168103611b16576001600160ff1b0383168303611b16576101045f5260205f209060011b8101908360011b015b818110611c505750611bb9565b5f8082556001820155600201611c43565b9035601e198236030181121561023c5701602081359101916001600160401b03821161023c578160061b3603831361023c57565b916020908281520191905f5b818110611cae5750505090565b90919260408060019261ffff8735611cc581611790565b1681526020870135611cd681611b2e565b611cdf81611b4c565b6020820152019401929101611ca1565b610100611da06102e693602084528035611d088161172f565b63ffffffff60e01b1660208501526020810135611d248161172f565b63ffffffff60e01b166040850152611d4c611d416040830161179c565b61ffff166060860152565b611d6c611d5b6060830161175e565b6001600160801b0319166080860152565b611d8c611d7b6080830161175e565b6001600160801b03191660a0860152565b60a081013560c085015260c0810190611c61565b91909260e0808201520191611c95565b15611db757565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b611e2c60ff5f5460081c16611e2781613672565b613672565b6001600160a01b038116611e8b5750611e4433613863565b61010060c95461ff0019161760c95560018060a01b03166001600160601b0360a01b60fb54161760fb5560018060a01b03166001600160601b0360a01b60fc54161760fc55565b611e4490613863565b634e487b7160e01b5f52603260045260245ffd5b903590601e198136030182121561023c57018035906001600160401b03821161023c5760200191813603831361023c57565b90821015611ef557611ef19160051b810190611ea8565b9091565b611e94565b6020919283604051948593843782019081520301902090565b908060209392818452848401375f828201840152601f01601f1916010190565b9160206102e6938181520191611f13565b15611f4b57565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b15611fac57565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b6163746976652070726f787960a01b6064820152608490fd5b9061201082610d74565b61201d6040519182610cf6565b828152809261202e601f1991610d74565b0190602036910137565b818110612043575050565b5f8155600101612038565b9190601f811161205d57505050565b610d27925f5260205f20906020601f840160051c83019310612087575b601f0160051c0190612038565b909150819061207a565b9092916001600160401b03811161092f576120b6816120b08454610df5565b8461204e565b5f601f82116001146120e85781906120e49394955f92610b955750508160011b915f199060031b1c19161790565b9055565b601f198216946120fb845f5260205f2090565b915f5b87811061213557508360019596971061211c575b505050811b019055565b01355f19600384901b60f8161c191690555f8080612112565b909260206001819286860135815501940191016120fe565b903590601e198136030182121561023c57018035906001600160401b03821161023c57602001918160051b3603831361023c57565b903590605e198136030182121561023c570190565b80545f8255806121a5575050565b610d27915f52601f60205f20910160051c810190612038565b90600160401b811161092f5781548183558082106121db57505050565b610d27925f52601f60205f20918180850160051c8401941680612205575b500160051c0190612038565b5f198501908154905f199060200360031b1c1690555f6121f9565b60ff81160361023c57565b356102e681612220565b6008111561023c57565b60081115611b5657565b356102e681612235565b906008811015611b565760ff80198354169116179055565b81358155600181019291612282602082018261214d565b906001600160401b03821161092f576122a99061229f83886121be565b955f5260205f2090565b8160051c915f5b83811061233c5750601f1981169003806122e3575b505050610d279293506122dc604060029201612249565b9101612253565b955f965f5b81811061230857505050019390935590918291906122dc604060026122c5565b90919760206123326001928461231d8d61222b565b919060ff809160031b9316831b921b19161790565b99019291016122e8565b5f5f5b602081106123545750838201556001016122b0565b989060206123686001928c61231d8661222b565b9201990161233f565b600160401b831161092f5780548382558084106123d1575b509061239981925f5260205f2090565b905f925b8484106123ab575050505050565b60036020826123c56123bf60019587612182565b8761226b565b0193019301929161239d565b80600302906003820403611b165783600302600381048503611b1657825f5260205f2091820191015b8181106124075750612389565b805f6003925561241960018201612197565b5f6002820155016123fa565b81604051928392833781015f815203902090565b9035601e198236030181121561023c5701602081359101916001600160401b03821161023c57813603831361023c57565b9035601e198236030181121561023c5701602081359101916001600160401b03821161023c578160051b3603831361023c57565b602081526124f06124e56124c66124b58580612439565b606060208701526080860191611f13565b6124d36020860186612439565b858303601f1901604087015290611f13565b92604081019061246a565b90916060601f19828603019101528083526020830160208260051b85010193835f91605e1982360301905b85841061252c575050505050505090565b90919293949596601f1982820301865287358381121561023c5784019060608101918035825261255f602082018261246a565b606060208501529384905260808301935f905b8082106125ac57505050604001359061258a82612235565b6008821015611b5657604001529660209081019695019360010192919061251b565b90919460208060019260ff89356125c281612220565b168152019601920190612572565b604051906125dd82610c53565b60606040838281528260208201520152565b6001600160401b03811161092f5760051b60200190565b6040519061261382610ca4565b815f81525f60208201526060604082015260608082015260606080820152606060a08201525f60c082015260e06040519161264d83610c53565b606083526060602084015260405161266481610cc0565b60608152606060208201525f604082015260608082015260408401520152565b604051608091906126958382610cf6565b6003815291601f1901825f5b8281106126ad57505050565b6020906126b8612606565b828285010152016126a1565b906003811015611ef55760051b0190565b5190610d2782610934565b81601f8201121561023c576020815191016126fa82610d74565b926127086040519485610cf6565b8284528282011161023c57815f926020928386015e8301015290565b9080601f8301121561023c57815161273b816125ef565b926127496040519485610cf6565b81845260208085019260051b82010192831161023c57602001905b8282106127715750505090565b8151815260209182019101612764565b919060608382031261023c576040519061279a82610c53565b819380516001600160401b03811161023c57826127b89183016126e0565b835260208101516001600160401b03811161023c57826127d99183016126e0565b60208401526040810151906001600160401b03821161023c57019160808383031261023c576040519261280b84610cc0565b80516001600160401b03811161023c57836128279183016126e0565b845260208101516001600160401b03811161023c57836128489183016126e0565b6020850152604081015160408501526060810151926001600160401b03841161023c576040936128789201612724565b60608401520152565b919060408382031261023c57825161289881610934565b926020810151906001600160401b03821161023c57016101008183031261023c576128c1610d38565b91815183526020820151602084015260408201516001600160401b03811161023c57816128ef9184016126e0565b604084015260608201516001600160401b03811161023c57816129139184016126e0565b606084015260808201516001600160401b03811161023c57816129379184016126e0565b608084015260a08201516001600160401b03811161023c578161295b9184016126e0565b60a084015261296c60c083016126d5565b60c084015260e08201516001600160401b03811161023c5761298e9201612781565b60e082015290565b906129ae6020919493946040845260408401906102a9565b931515910152565b6040513d5f823e3d90fd5b805115611ef55760200190565b805160011015611ef55760400190565b805160021015611ef55760600190565b8051821015611ef55760209160051b010190565b6008821015611b565752565b90604051612a1b81610c53565b60028193612a2881610e2d565b8352612a3660018201610e2d565b60208401520190815491612a49836125ef565b92612a576040519485610cf6565b80845260208401915f5260205f20915f905b828210612a7a575050505060400152565b604051612a8681610c53565b84548152604051600186018054808352612aa760208401925f5260205f2090565b905f915b81601f840110612e8c5784600197946003979460209794612bce945491818110612e7b575b818110612e66575b818110612e51575b818110612e3c575b818110612e29575b818110612e14575b818110612dff575b818110612dea575b818110612dd5575b818110612dc0575b818110612dab575b818110612d96575b818110612d81575b818110612d6c575b818110612d57575b818110612d42575b818110612d2d575b818110612d18575b818110612d03575b818110612cee575b818110612cd9575b818110612cc4575b818110612caf575b818110612c9a575b818110612c85575b818110612c70575b818110612c5b575b818110612c46575b818110612c31575b818110612c1c575b818110612c07575b10612bfa575b500382610cf6565b83820152612bec612be360028a015460ff1690565b60408301612a02565b815201940191019092612a69565b60f81c815286015f612bc6565b60ff60f084901c168452928901928b01612bc0565b60ff60e884901c168452928901928b01612bb8565b60ff60e084901c168452928901928b01612bb0565b60ff60d884901c168452928901928b01612ba8565b60ff60d084901c168452928901928b01612ba0565b60ff60c884901c168452928901928b01612b98565b60ff60c084901c168452928901928b01612b90565b60ff60b884901c168452928901928b01612b88565b60ff60b084901c168452928901928b01612b80565b60ff60a884901c168452928901928b01612b78565b60ff60a084901c168452928901928b01612b70565b60ff609884901c168452928901928b01612b68565b60ff609084901c168452928901928b01612b60565b60ff608884901c168452928901928b01612b58565b60ff608084901c168452928901928b01612b50565b60ff607884901c168452928901928b01612b48565b60ff607084901c168452928901928b01612b40565b60ff606884901c168452928901928b01612b38565b60ff606084901c168452928901928b01612b30565b60ff605884901c168452928901928b01612b28565b60ff605084901c168452928901928b01612b20565b60ff604884901c168452928901928b01612b18565b60ff604084901c168452928901928b01612b10565b60ff603884901c168452928901928b01612b08565b60ff603084901c168452928901928b01612b00565b60ff602884901c168452928901928b01612af8565b60ff838b1c168452928901928b01612af0565b60ff601884901c168452928901928b01612ae8565b60ff601084901c168452928901928b01612ae0565b60ff600884901c168452928901928b01612ad8565b60ff83168452928901928b01612ad0565b92600161040060209261304e8754612ea98360ff831660ff169052565b600881901c60ff1683870152601081901c60ff166040840152601881901c60ff16606084015280861c60ff166080840152602881901c60ff1660a0840152603081901c60ff1660c0840152603881901c60ff1660e0840152604081901c60ff16610100840152604881901c60ff16610120840152605081901c60ff16610140840152605881901c60ff16610160840152606081901c60ff16610180840152606881901c60ff166101a0840152607081901c60ff166101c0840152607881901c60ff166101e0840152608081901c60ff16610200840152608881901c60ff16610220840152609081901c60ff16610240840152609881901c60ff1661026084015260a081901c60ff1661028084015260a881901c60ff166102a084015260b081901c60ff166102c084015260b881901c60ff166102e084015260c081901c60ff1661030084015260c881901c60ff1661032084015260d081901c60ff1661034084015260d881901c60ff1661036084015260e081901c60ff1661038084015260e881901c60ff166103a084015260f081901c60ff166103c084015260f81c6103e0830152565b019401920191612aab565b80516001600160801b03191682526102e6916020828101516001600160e01b0319169082015260408281015163ffffffff1916908201526060828101516001600160801b031916908201526080820151608082015260a082015160a082015260c082015160c08201526101606131156130e360e085015161018060e08601526101808501906102a9565b6101008581015161ffff16908501526101208581015161ffff16908501526101408501518482036101408601526102a9565b920151906101608184039101526102a9565b906040606082019261ffff815116835263ffffffff6020820151166020840152015191606060408301529060c0810192915f905b6003821061316a575050505090565b90919293602080613187600193605f1988820301865288516102a9565b96019201920190929161315b565b6102e69160a06132196131f06131de6131cc6131ba875160c0885260c08801906102a9565b602088015187820360208901526102a9565b60408701518682036040880152613059565b606086015185820360608701526102a9565b604060206080870151868403608088015261ffff815116845201519181602082015201906102a9565b9201519060a0818403910152613127565b906102e691602081526132bb60c0835161ffff60f01b815116602085015261ffff60f01b602082015116604085015263ffffffff60e01b604082015116606085015261ffff60f01b606082015116608085015261ffff60f01b60808201511660a08501526132a860a0820151838601906001600160801b0319169052565b01516001600160601b03191660e0830152565b60406132d96020840151610120610100850152610140840190613059565b92015190610120601f1982850301910152613195565b9081526008821015611b565760219160f81b60208201520190565b6040516001600160f81b0319602082015260018152919061332c602184610cf6565b61333581613ad4565b969391509150156136115760fc549460a086901c60ff166135af575b6040840191613364604084510151613eee565b90156135065780613376600192611b4c565b146135a4576133836125d0565b5061338c612684565b965f906133a9906001600160a01b03165b6001600160a01b031690565b905b600381106135125750506020604060e06133c48a6129c1565b510151015101516133fb61065f6133e26133dd84610dd7565b612a0e565b9260208401516020815191012090602081519101201490565b6135065761342d61065f604060e06134128c6129c1565b51015101515183516020815191012090602081519101201490565b613506576134489060e06134408a6129c1565b510151614085565b9790156135065761345b61065f826141b5565b613506579161348293916040608061347561065f966129c1565b5101519351015192614464565b6134fe57505f6134bc6134a26134b060209460405192839187830161322a565b03601f198101835282610cf6565b60405191828092610dc5565b039060025afa156134f9576134f5826134f05f516134e2604051968792602084016132ef565b03601f198101865285610cf6565b6145b7565b9190565b6129b6565b9250505f9190565b505050509250505f9190565b6135465f61352883604060a089015101516126c4565b516040518093819263c1c1d5c160e01b835286159060048401612996565b0381865afa80156134f9575f915f91613580575b50613565838c6129ee565b5215613573576001016133ab565b50505050509250505f9190565b905061359e91503d805f833e6135968183610cf6565b810190612881565b5f61355a565b5050509250505f9190565b602084016135ee6135d560c06135dc6135d56080865101515f5260fd60205260405f2090565b5460ff1690565b935101515f5260fe60205260405f2090565b9015908115613608575b50156133515750509250505f9190565b9050155f6135f8565b509250505f9190565b6033546001600160a01b0316330361362e57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b1561367957565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b9081602091031261023c575190565b156136e857565b60405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608490fd5b60809060208152602e60208201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960408201526d6f6e206973206e6f74205555505360901b60608201520190565b906137ba7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1690565b156137c95750610d2790614717565b6040516352d1902d60e01b8152906020826004816001600160a01b0387165afa5f928161382c575b5061380f5760405162461bcd60e51b8152806110796004820161373f565b610d279261109b5f5160206156f55f395f51905f525f94146136e1565b61384691935060203d6020116110ca576110bb8183610cf6565b915f6137f1565b1561385457565b63bae6e2a960e01b5f5260045ffd5b606580546001600160a01b0319908116909155603380549182166001600160a01b0393841690811790915591167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b6040516001600160f81b031960208201526001815292916138f9916138f4906138e0602187610cf6565b60fc546001600160a01b0316923691610d8f565b6147ae565b901561390a57611ef191925061330a565b505f9190565b6040519061391d82610c6e565b5f60c0838281528260208201528260408201528260608201528260808201528260a08201520152565b6040519061018082018281106001600160401b0382111761092f576040526060610160835f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201528260e08201525f6101008201525f610120820152826101408201520152565b604051906139bc82610c89565b60606020835f81520152565b6060906040516139d88382610cf6565b80925f5b8181106139e857505050565b8082602092850152016139dc565b60405190613a0382610c53565b815f81525f602082015260406118f96139c8565b6040519060c082018281106001600160401b0382111761092f57604052816060815260606020820152613a48613946565b6040820152606080820152613a5b6139af565b608082015260a06118f96139f6565b61ffff166103f2019061ffff8211611b1657565b61ffff60029116019061ffff8211611b1657565b61ffff60049116019061ffff8211611b1657565b61ffff16610242019061ffff8211611b1657565b9063ffffffff8091169116019063ffffffff8211611b1657565b90613add613910565b50613ae6613946565b50613aef613a17565b506001916020810151906040810190604082510151606060e08501515114801590613dbc575b8015613dab575b613d9c57606060e0820151511490811591613d8a575b8115613d78575b50613d6a57600561ffff613b5460a0855101515161ffff1690565b1603613d5b57815160408151511490811591613d4a575b8115613d39575b50613d2a5760808251015161ffff6020613b8f8361ffff90511690565b92015151911603613d1b576103fc63ffffffff613be9613bcf613bca613bc5613bc060808951015161ffff90511690565b613a6a565b613a7e565b613a92565b855160a001516020015163ffffffff169061ffff16613aba565b161115613d0c575192613d01613d07613c07865161ffff60f01b1690565b6020870151613ce5906001600160f01b031916916134a2613c3260408b015163ffffffff60e01b1690565b60608b01518b906001600160f01b03191660808201516001600160f01b03191690613c7d60c0613c6d60a08601516001600160801b03191690565b9401516001600160601b03191690565b6040516001600160f01b0319978816602082015298871660228a01526001600160e01b031990941660248901528516602888015293909316602a8601526001600160801b0319909216602c8501526001600160601b0319909116603c84015282906050820190565b6134a2613cf187614912565b6040519485936020850190610dc5565b90610dc5565b915190565b631350008b60e31b5f5260045ffd5b630c6543ad60e01b5f5260045ffd5b6346ac673f60e01b5f5260045ffd5b60409150606001515114155f613b72565b602081015151604014159150613b6b565b63213d071160e21b5f5260045ffd5b623dc25960e41b5f5260045ffd5b6040915061016001515114155f613b39565b61014081015151603c14159150613b32565b633c20ffcf60e11b5f5260045ffd5b506040610160850151511415613b1c565b50603c610140850151511415613b15565b908154613dd9816125ef565b92613de76040519485610cf6565b81845260208401905f5260205f205f915b838310613e055750505050565b60026020600192604051613e1881610c89565b604051613e2481610cdb565b61ffff8754168152815260ff8587015416613e3e81611b4c565b83820152815201920192019190613df8565b60405190613e5d82610c6e565b6101015460e081901b6001600160e01b0319908116845260c082901b166020840152604081811c61ffff16908401528290613eb790613ea69060301b6001600160801b03191690565b6001600160801b0319166060830152565b613ed8613ec76101025460801b90565b6001600160801b0319166080830152565b6101035460a082015260c06118f9610104613dcd565b905f91613ef9613e50565b60208201516001600160e01b03191660208201516001600160e01b03191616613f39613f2c835163ffffffff60e01b1690565b6001600160e01b03191690565b60608401516001600160e01b03199092161492906001600160801b03191660808301516001600160801b03191616613f8c613f7f60608501516001600160801b03191690565b6001600160801b03191690565b906001600160801b0319161460c082015160a08401511490613fb461010084015161ffff1690565b61ffff613fd0613fc9604088015161ffff1690565b61ffff1690565b9116149260c05f950190815151915f5b838110614029575b5050505084614021575b5083614019575b5082614011575b508161400b57509190565b90509190565b91505f614000565b92505f613ff9565b93505f613ff2565b6140348183516129ee565b5180515161ffff1661ffff614052613fc961012088015161ffff1690565b911611156140635750600101613fe0565b97505050505095506020600193015161407b81611b4c565b955f808080613fe8565b9060400190815151915f5b8381106140a35750505050600190600790565b6140ae8183516129ee565b5160408401516140d060606040830151845111159201516020840151906149da565b8161410a575b506140e45750600101614090565b92505050604091500151906140f88261223f565b6141018261223f565b60068214159190565b90505f6140d6565b5f19810191908211611b1657565b600119810191908211611b1657565b6101b319810191908211611b1657565b9060018201809211611b1657565b9060028201809211611b1657565b9060048201809211611b1657565b9081602091031261023c57516102e681610934565b916141a7906141996102e695936060865260608601906102a9565b9084820360208601526102a9565b9160408184039101526102a9565b805160fb545f928392839283928392916141d7906001600160a01b031661339d565b905b828410614213575b5050505015928361420b575b5082614203575b50816141fe575090565b905090565b91505f6141f4565b92505f6141ed565b9091929496614220612606565b5061422a84614112565b8603614363575061423b85826129ee565b51945b61424881836129ee565b51514211978861434a575b88156143435750606061426682846129ee565b510151956020608060a061427a85876129ee565b5101519201918251986142a16040519a8b9384936326995c1560e21b85526004850161417e565b0381875afa9687156134f9575f97614313575b50861561430d576142eb7f89f72d7c488e5b53a77c23ebcb36970ef7eb5bcf6658e9b8292cfbe4703a847391516020815191012090565b146142fb576001019291906141d9565b5050505091506001915f8080806141e1565b506141e1565b61433591975060203d811161433c575b61432d8183610cf6565b810190614169565b955f6142b4565b503d614323565b95506141e1565b9750602061435882846129ee565b510151421097614253565b93946143776143718261413f565b836129ee565b519561438285614120565b82036143e3575060015f5260ff6020526143ce6135d57ff806280aa4dfe145596c627f696302876be30d4ea721e7e2b62aecde7954710a5b60406143c685876129ee565b51015161158f565b94855b6143db575061423e565b9795506141e1565b946143fb60c06143f384866129ee565b510151151590565b614406575b856143d1565b5f805260ff602052945061443c6135d57f03d616f3758432b4d7452e2e9011612152589bfc903ce751686613c478b2af5f6143ba565b94614400565b602081519101519060208110614456575090565b5f199060200360031b1b1690565b9261447961016061447e929493940151614a3d565b614442565b602082019060205f6144ab613d016134b086516134a28660808b0151015160405194859389850190610dc5565b039060025afa156134f9575f51036145af576144ca6040830151614912565b60fb549092906020906144e5906001600160a01b031661339d565b60608301516040516326995c1560e21b81529791958892839261450b926004850161417e565b0381865afa9485156134f9575f95614583575b505190516040516326995c1560e21b815293602093859390928492839261454992916004850161417e565b03915afa9081156134f9575f916145645750816141fe575090565b61457d915060203d60201161433c5761432d8183610cf6565b5f6141f4565b602093919550916145a46145499593853d871161433c5761432d8183610cf6565b95919350919361451e565b505050505f90565b6008811015611b5657801590811561461d575b8115614608575b81156145f3575b81156145e2575090565b600591506145ef8161223f565b1490565b90506145fe8161223f565b60048114906145d8565b90506146138161223f565b60028114906145d1565b90506146288161223f565b60018114906145ca565b9161463c83614717565b6001600160a01b0383167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28151159081159161470f575b5061467f575050565b614704915f8060405193614694606086610cf6565b602785527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c6020860152660819985a5b195960ca1b6040860152602081519101845af43d15614707573d916146e883610d74565b926146f66040519485610cf6565b83523d5f602085013e615522565b50565b606091615522565b90505f614676565b803b156147535760018060a01b03166001600160601b0360a01b5f5160206156f55f395f51905f525416175f5160206156f55f395f51905f5255565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b604051906147bb82610c53565b6147c3613910565b82526147cd613946565b60208301526147da613a17565b6040830152816103fc8251111561486c57506147fd6147f882614a6a565b614d97565b9283614809835161412f565b036148805761481f61481a83614a8c565b614f0a565b94901561487657906148346148399284614aa2565b6150a4565b92901561486c575061484d61485291614ac4565b61523f565b61485a610d48565b92835260208301526040820152600191565b93925050505f9190565b505f949293505050565b505f9391925050565b91956148ef956004999560a0956102e69f9e9c9a9499613d019e9a6001600160801b031916875263ffffffff60e01b16601087015263ffffffff191660148601526001600160801b03191660308501526040840152606083015260808201520190610dc5565b6001600160f01b031960f093841b811682529190921b1660028201520190610dc5565b6102e660206134a261492a61010085015161ffff1690565b614941600882901c60ff165b9160081b61ff001690565b1761495261012086015161ffff1690565b614962600882901c60ff16614936565b179461497681516001600160801b03191690565b818501519096906001600160e01b0319169261499a604084015163ffffffff191690565b60608401516001600160801b031916608085015160a08601519060c08701519260e0880151946101606101408a0151990151996040519e8f9d8e01614889565b906010825114801590614a31575b614a2b575f5b601081106149fe57505050600190565b614a0881846129ee565b5160ff614a1583856129ee565b511611614a24576001016149ee565b5050505f90565b50505f90565b506010815114156149e8565b8051602011614a5b57602080614a5281612006565b92018183015e90565b6343733a0960e11b5f5260045ffd5b80516101b411614a5b5760046101d0614a8282612006565b9201602083015e90565b8051603011614a5b5760306020614a8282612006565b90806101b401806101b411611b1657825110614a5b576101d4614a8282612006565b80516101b011614a5b576101806050614a8282612006565b8051600211614a5b5760026020614a8282612006565b8051600411614a5b5760026022614a8282612006565b8051600811614a5b5760046024614a8282612006565b8051601c11614a5b576010602c614a8282612006565b8051600a11614a5b5760026028614a8282612006565b8051600c11614a5b576002602a614a8282612006565b8051603011614a5b576014603c614a8282612006565b805161024211614a5b576002610260614a8282612006565b9080610242018061024211611b1657825110614a5b57610262614a8282612006565b9060028101808211611b1657825110614a5b576020600291614bd183612006565b930101602083015e90565b9060048101808211611b1657825110614a5b576020600491614bd183612006565b8051604011614a5b5760406020614a8282612006565b8051608011614a5b5760406060614a8282612006565b805161020011614a5b5761018060a0614a8282612006565b805161024011614a5b576040610220614a8282612006565b8051601011614a5b5760106020614a8282612006565b8051601411614a5b5760046030614a8282612006565b8051603011614a5b57601c6034614a8282612006565b8051604011614a5b5760106050614a8282612006565b8051606011614a5b5760206060614a5282612006565b8051608011614a5b5760206080614a5282612006565b805160a011614a5b57602060a0614a5282612006565b805161010011614a5b57606060c0614a8282612006565b805161010211614a5b576002610120614a8282612006565b805161010411614a5b576002610122614a8282612006565b805161014011614a5b57603c610124614a8282612006565b805161018011614a5b576040610160614a8282612006565b9190818101808211611b1657835110614a5b57602090614bd183612006565b603f8111611b165760100a90565b905f9180515f915b818310614dab57505050565b9091938151851015611ef5576020858301015160f81c614dfb614de6600f8360041c9316614de0614ddb8a611afe565b614d89565b90611b1b565b91614de0614ddb614df68a611afe565b61413f565b8101809111611b16578101809111611b1657936001019190614d9f565b80516020909101516001600160f01b0319811692919060028210614e3a575050565b6001600160f01b031960029290920360031b82901b16169150565b80516020909101516001600160e01b0319811692919060048210614e77575050565b6001600160e01b031960049290920360031b82901b16169150565b9060208251920151916001600160801b031983169260108210614eb3575050565b6001600160801b031960109290920360031b82901b16169150565b9060208251920151916001600160601b031983169260148210614eef575050565b6001600160601b031960149290920360031b82901b16169150565b614f12613910565b90614f24614f1f82614adc565b614e18565b9160fd60f81b6001600160f01b031984160161509b57614f46614f1f83614af2565b91607f60f91b6001600160f01b031984160161509157614f6d614f6882614b08565b614e55565b6001600160e01b0319811661508657614f8d614f8883614b1e565b614e92565b926f6c658dcc0863b3566bf5f24c6a80f9f960801b6001600160801b031985160161507a575091615053826150426150759695615031614fd2614f1f61506498614b34565b91615020614ff3614fee614fe8614f1f89614b4a565b97614b60565b614ece565b9961500f614fff610d57565b6001600160f01b0319909e168e52565b6001600160f01b03191660208d0152565b6001600160e01b03191660408b0152565b6001600160f01b0319166060890152565b6001600160f01b0319166080870152565b6001600160801b03191660a0850152565b6001600160601b03191660c0830152565b600191565b959450505050505f9190565b5050929150505f9190565b50929150505f9190565b929150505f9190565b906150ad613a17565b916150b66139af565b906150d16150c9613fc96147f884614b76565b61ffff168352565b6150ea61ffff6150e3845161ffff1690565b1682614b8e565b6020830152615106613fc9615101845161ffff1690565b613aa6565b9261510f6139f6565b9361512b615123613fc96147f88487614bb0565b61ffff168652565b61ffff61513a865161ffff1690565b16600181109081156151fe575b506151f4576151e092916151a76151606151ac9361414d565b6151a06151796151956151826151796147f8868b614bdc565b63ffffffff1690565b63ffffffff1660208c019081529361415b565b925163ffffffff1690565b9085614d6a565b615424565b60408501526151ba81614bfd565b85526151c581614c13565b60208601526151d661484d82614c29565b6040860152614c41565b6060840152608083015260a0820152600191565b505f959350505050565b60059150115f615147565b90602082519201519163ffffffff19831692601c8210615227575050565b63ffffffff19601c9290920360031b82901b16169150565b906118a861524b613946565b9261526961525b614f8883614c59565b6001600160801b0319168552565b615289615278614f6883614c6f565b6001600160e01b0319166020860152565b6152ab61529d61529883614c85565b615209565b63ffffffff19166040860152565b6152cb6152ba614f8883614c9b565b6001600160801b0319166060860152565b6152d761447982614cb1565b60808501526152e861447982614cc7565b60a08501526152f961447982614cdd565b60c085015261530781614cf3565b60e085015261532a61531e613fc96147f884614d0a565b61ffff16610100860152565b61534861533c613fc96147f884614d22565b61ffff16610120860152565b61535181614d3a565b610140850152614d52565b919060408382031261023c57825161537381610934565b926020810151906001600160401b03821161023c57019080601f8301121561023c5781516153a0816125ef565b926153ae6040519485610cf6565b81845260208085019260051b8201019183831161023c5760208201905b8382106153da57505050505090565b81516001600160401b03811161023c576020916153fc878480948801016126e0565b8152019101906153cb565b9190602061541f6003926040865260408601906102a9565b930152565b5f9061544e926154326139c8565b506040518080958194635b732b7d60e11b835260048301615407565b03916001600160a01b03165afa9081156134f9575f905f926154fd575b50156154ee57615479612684565b505f5b600381106154bc57506154b36154926060610d66565b9161549c816129c1565b5183526154a8816129ce565b5160208401526129de565b51604082015290565b806154d26154cc600193856129ee565b516155bb565b6154dc82856129ee565b526154e781846129ee565b500161547c565b636237e47b60e11b5f5260045ffd5b905061551b91503d805f833e6155138183610cf6565b81019061535c565b905f61546b565b919290156155845750815115615536575090565b3b1561553f5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156155975750805190602001fd5b60405162461bcd60e51b8152602060048201529081906110799060248301906102a9565b906060918051806155ca575050565b90925060038160021c0290600381169081156156b95750015f19015b6040519281845260208401918401916003600460208501935f5160206156d55f395f51905f52605b527804080c1014181c2024282c3034383c4044484c5054585c6064603b526ef8fcf800fcd0d4d8dce0e4e8ecf0f4601a525b0191825160ff81165160061c81601e1a515f5160206156d55f395f51905f52161760061c81601d1a515f5160206156d55f395f51905f52161760061c90601c1a515f5160206156d55f395f51905f52161781520190828210156156a857600390600490615640565b505060405f9201604052525f606052565b613d3d91508401511860ff81161590601e1a150190036155e656fefc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca264697066735822122055b677081c87cfe8bb34853c524afbd78964980187cdabb3b9a5255137385df164736f6c634300081e0033
External libraries
LibForcedInclusion : 0xd1a27F331c17eD8Cbb6DAbce67A42d6b8a6B0e14
LibInboxSetup : 0xf88Ef5437749A225621101BE8C1BE1A0cE967758