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
- 2026-06-23T13:33:06.023348Z
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.26;
/// @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.26;
// 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.26;
// 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.26;
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":false,"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":{},"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
0x60c060405230608052348015610013575f5ffd5b5061001c610021565b6100dd565b5f54610100900460ff161561008c5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146100db575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60805160a05161597361011a5f395f61022901525f818161098c015281816109cc01528181610ccc01528181610d0c0152610d8701526159735ff3fe6080604052600436106101db575f3560e01c806352d1902d116100fd5780638456cb5911610092578063cf12f55511610062578063cf12f555146105e5578063e2e282941461062f578063e30c39781461064e578063f2fde38b1461066b575f5ffd5b80638456cb59146105055780638abf6077146105195780638da5cb5b1461052d578063b684252f1461054a575f5ffd5b8063715018a6116100cd578063715018a6146104aa578063769d87e7146104be57806379ba5097146104dd57806383801580146104f1575f5ffd5b806352d1902d1461041b57806354e219131461043d5780635c975abb1461046b578063610de4801461048b575f5ffd5b80633075db56116101735780633f4ba83a116101435780633f4ba83a146103a85780634bc7eea4146103bc5780634c0977a9146103db5780634f1ef28614610408575f5ffd5b80633075db561461032857806332f555ec1461033c5780633659cfe61461036a5780633a34301414610389575f5ffd5b80630d23d71b116101ae5780630d23d71b146102aa578063123ac29e146102c9578063184b9559146102ea5780631f3be09614610309575f5ffd5b806301d711f4146101df57806304f3bcec1461021b5780630570e1fc1461024d578063089a168f1461027d575b5f5ffd5b3480156101ea575f5ffd5b5060fc546101fe906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610226575f5ffd5b507f00000000000000000000000000000000000000000000000000000000000000006101fe565b348015610258575f5ffd5b5060fc5461026d90600160a01b900460ff1681565b6040519015158152602001610212565b348015610288575f5ffd5b5061029c610297366004613661565b61068a565b6040516102129291906136c6565b3480156102b5575f5ffd5b5060fb546101fe906001600160a01b031681565b3480156102d4575f5ffd5b506102e86102e33660046136e0565b6106a7565b005b3480156102f5575f5ffd5b506102e8610304366004613731565b6106fa565b348015610314575f5ffd5b506102e8610323366004613771565b61083e565b348015610333575f5ffd5b5061026d61096a565b348015610347575f5ffd5b5061026d6103563660046137e9565b60fe6020525f908152604090205460ff1681565b348015610375575f5ffd5b506102e8610384366004613800565b610982565b348015610394575f5ffd5b506102e86103a3366004613826565b610a49565b3480156103b3575f5ffd5b506102e8610aa8565b3480156103c7575f5ffd5b506102e86103d6366004613891565b610b03565b3480156103e6575f5ffd5b506103fa6103f5366004613a77565b610b8e565b604051610212929190613abb565b6102e8610416366004613b06565b610cc2565b348015610426575f5ffd5b5061042f610d7b565b604051908152602001610212565b348015610448575f5ffd5b5061026d6104573660046137e9565b60fd6020525f908152604090205460ff1681565b348015610476575f5ffd5b5061026d60c954610100900460ff1660021490565b348015610496575f5ffd5b506102e86104a5366004613771565b610e2c565b3480156104b5575f5ffd5b506102e8610f5c565b3480156104c9575f5ffd5b5061026d6104d8366004613b50565b610f6d565b3480156104e8575f5ffd5b506102e8610f80565b3480156104fc575f5ffd5b506102e8610ff7565b348015610510575f5ffd5b506102e8611065565b348015610524575f5ffd5b506101fe6110ba565b348015610538575f5ffd5b506033546001600160a01b03166101fe565b348015610555575f5ffd5b506101015461010254610103546105979260e081811b93640100000000830490911b9261ffff600160401b84041692600160501b9004608090811b92901b9086565b604080516001600160e01b0319978816815296909516602087015261ffff909316938501939093526001600160801b03199081166060850152909116608083015260a082015260c001610212565b3480156105f0575f5ffd5b5061026d6105ff366004613b8e565b60ff60208181525f9384526040909320825180840185018051928152908501939094019290922091909252541681565b34801561063a575f5ffd5b506102e8610649366004613826565b6110c8565b348015610659575f5ffd5b506065546001600160a01b03166101fe565b348015610676575f5ffd5b506102e8610685366004613800565b61111f565b5f606061069e61069984613fbe565b611190565b91509150915091565b6106af61184d565b806101016106bd828261428e565b9050507f8867fcb26463d2f77f8c8f24316221d64d8b4821bf4dea1b4c9b83d4ba271c45816040516106ef9190614451565b60405180910390a150565b5f54610100900460ff161580801561071857505f54600160ff909116105b806107315750303b15801561073157505f5460ff166001145b6107995760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b5f805460ff1916600117905580156107ba575f805461ff0019166101001790555b6107c3846118a7565b60fb80546001600160a01b038086166001600160a01b03199283161790925560fc8054928516929091169190911790558015610838575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b61084661184d565b805f5b81811015610963575f85815260ff6020526040902084848381811061087057610870614510565b90506020028101906108829190614524565b604051610890929190614566565b9081526040519081900360200190205460ff161561095b575f85815260ff602052604090208484838181106108c7576108c7614510565b90506020028101906108d99190614524565b6040516108e7929190614566565b908152604051908190036020019020805460ff19169055847fee365795c95effb059e7128967d8e0dce7b2eaaf750bb4c422df5411fb8aedfd85858481811061093257610932614510565b90506020028101906109449190614524565b60405161095292919061459d565b60405180910390a25b600101610849565b5050505050565b5f600261097960c95460ff1690565b60ff1614905090565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036109ca5760405162461bcd60e51b8152600401610790906145b0565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166109fc611905565b6001600160a01b031614610a225760405162461bcd60e51b8152600401610790906145fc565b610a2b81611920565b604080515f80825260208201909252610a4691839190611928565b50565b610a5161184d565b5f82815260fd6020908152604091829020805460ff1916841515908117909155915191825283917fe9c8da9c89154486636f96dbbf87f6cdf819637dda597383e5b1533b446b51d291015b60405180910390a25050565b610ab0611a97565b610ac460c9805461ff001916610100179055565b6040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa9060200160405180910390a1610b01335f611ac8565b565b610b0b61184d565b806101008484604051610b1f929190614566565b908152604051908190036020019020610b388282614a74565b5050604051610b4a9084908490614566565b60405180910390207f540fc9dd1a61f44f6860558982bac073b37667cb331897eb59633910cfd0382282604051610b819190614bf2565b60405180910390a2505050565b805160208183018101805161010082529282019190930120915280548190610bb590614648565b80601f0160208091040260200160405190810160405280929190818152602001828054610be190614648565b8015610c2c5780601f10610c0357610100808354040283529160200191610c2c565b820191905f5260205f20905b815481529060010190602001808311610c0f57829003601f168201915b505050505090806001018054610c4190614648565b80601f0160208091040260200160405190810160405280929190818152602001828054610c6d90614648565b8015610cb85780601f10610c8f57610100808354040283529160200191610cb8565b820191905f5260205f20905b815481529060010190602001808311610c9b57829003601f168201915b5050505050905082565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610d0a5760405162461bcd60e51b8152600401610790906145b0565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610d3c611905565b6001600160a01b031614610d625760405162461bcd60e51b8152600401610790906145fc565b610d6b82611920565b610d7782826001611928565b5050565b5f306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e1a5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610790565b505f5160206158f75f395f51905f5290565b610e3461184d565b805f5b81811015610963575f85815260ff60205260409020848483818110610e5e57610e5e614510565b9050602002810190610e709190614524565b604051610e7e929190614566565b9081526040519081900360200190205460ff16610f54575f85815260ff60205260409020600190858584818110610eb757610eb7614510565b9050602002810190610ec99190614524565b604051610ed7929190614566565b908152604051908190036020019020805491151560ff19909216919091179055847f775b5995b6d311d1ac0f46050a5a41564043b346e952189284ec57bd4c0d58dd858584818110610f2b57610f2b614510565b9050602002810190610f3d9190614524565b604051610f4b92919061459d565b60405180910390a25b600101610e37565b610f6461184d565b610b015f611ad0565b5f610f788383611ae9565b509392505050565b60655433906001600160a01b03168114610fee5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610790565b610a4681611ad0565b610fff61184d565b60fc805460ff600160a01b808304821615810260ff60a01b1990931692909217928390556040517fcafd71daf69ac558b30d115a7b5a9751259ac2352764cdf5b7038c74dc43ccb49361105b9390049091161515815260200190565b60405180910390a1565b61106d611b8c565b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200160405180910390a1610b01336001611ac8565b5f6110c3611905565b905090565b6110d061184d565b5f82815260fe6020908152604091829020805460ff1916841515908117909155915191825283917fa8796d5584281f38b5f5c7f2ff1ee978acc17db51930ab666a66712c2d9f93ac9101610a9c565b61112761184d565b606580546001600160a01b0383166001600160a01b031990911681179091556111586033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b604080516001600160f81b031960208201528151600181830301815260219091019091525f906060908280806111c587611bbe565b9450945050509250826111e057505f96929550919350505050565b60fc54600160a01b900460ff16156112475760208088018051608001515f90815260fd8352604080822054925160c00151825260fe909352919091205460ff918216911681158061122f575080155b1561124457505f989497509395505050505050565b50505b5f5f61125a896040015160400151611e83565b925090508061127357505f989497509395505050505050565b8015806112915750600182600181111561128f5761128f614166565b145b156112a657505f989497509395505050505050565b5060606112cd60405180606001604052806060815260200160608152602001606081525090565b6040805160038082526080820190925290816020015b6112eb61346d565b8152602001906001900390816112e35790505091505f5b60038110156113e55760fc5460a0860151604001518215915f916001600160a01b039091169063c1c1d5c190856003811061133f5761133f614510565b6020020151846040518363ffffffff1660e01b8152600401611362929190614d3d565b5f60405180830381865afa15801561137c573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526113a39190810190614f5d565b8685815181106113b5576113b5614510565b60209081029190910101529050806113db57505f9c989b50979950505050505050505050565b5050600101611302565b505f825f815181106113f9576113f9614510565b602002602001015160e00151604001516020015190506101008160405161142091906150c2565b90815260200160405180910390206040518060600160405290815f8201805461144890614648565b80601f016020809104026020016040519081016040528092919081815260200182805461147490614648565b80156114bf5780601f10611496576101008083540402835291602001916114bf565b820191905f5260205f20905b8154815290600101906020018083116114a257829003601f168201915b505050505081526020016001820180546114d890614648565b80601f016020809104026020016040519081016040528092919081815260200182805461150490614648565b801561154f5780601f106115265761010080835404028352916020019161154f565b820191905f5260205f20905b81548152906001019060200180831161153257829003601f168201915b5050505050815260200160028201805480602002602001604051908101604052809291908181526020015f905b8282101561165b578382905f5260205f2090600302016040518060600160405290815f82015481526020016001820180548060200260200160405190810160405280929190818152602001828054801561161057602002820191905f5260205f20905f905b825461010083900a900460ff168152602060019283018181049485019490930390920291018084116115e15790505b5050509183525050600282015460209091019060ff16600781111561163757611637614166565b600781111561164857611648614166565b815250508152602001906001019061157c565b50505091525050602081810151805190820120835191840191909120919350148061169357505f9b979a509698505050505050505050565b5f845f815181106116a6576116a6614510565b60209081029190910181015160e0810151604001515186518051908401208151919093012090925014806116e957505f9d999c50989a5050505050505050505050565b505050505f5f611716845f8151811061170457611704614510565b602002602001015160e00151846120b5565b925090508061173257505f9b979a509698505050505050505050565b505f61173d8461216d565b90508061175757505f9b979a509698505050505050505050565b505f61178a845f8151811061176e5761176e614510565b60200260200101516080015188888f6040015160400151612485565b9050806117a457505f9b979a509698505050505050505050565b5060028b6040516020016117b891906152ed565b60408051601f19818403018152908290526117d2916150c2565b602060405180830381855afa1580156117ed573d5f5f3e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061181091906153b1565b816040516020016118229291906153c8565b604051602081830303815290604052975061183c81612680565b9b979a509698505050505050505050565b6033546001600160a01b03163314610b015760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610790565b5f54610100900460ff166118cd5760405162461bcd60e51b8152600401610790906153f0565b6118d561270b565b6118f36001600160a01b038216156118ed5781611ad0565b33611ad0565b5060c9805461ff001916610100179055565b5f5160206158f75f395f51905f52546001600160a01b031690565b610a4661184d565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156119605761195b83612731565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156119ba575060408051601f3d908101601f191682019092526119b7918101906153b1565b60015b611a1d5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610790565b5f5160206158f75f395f51905f528114611a8b5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610790565b5061195b8383836127cc565b611aab60c954610100900460ff1660021490565b610b015760405163bae6e2a960e01b815260040160405180910390fd5b610d7761184d565b606580546001600160a01b0319169055610a46816127f0565b6040516001600160f81b031960208201525f90606090829060210160408051601f198184030181526020601f880181900481028401810190925286835292505f918291611b5d919089908990819084018382808284375f920191909152505060fc546001600160a01b031691506128419050565b9150915081611b74575f8394509450505050611b85565b611b7d81611190565b945094505050505b9250929050565b611ba060c954610100900460ff1660021490565b15610b015760405163bae6e2a960e01b815260040160405180910390fd5b5f611bc76134b6565b611bcf6134f1565b6060611bd9613556565b6020860151604080880151015160e08201515160019750919450906060141580611c0a575083610140015151603c14155b80611c1c575083610160015151604014155b15611c3a57604051633c20ffcf60e11b815260040160405180910390fd5b8060e00151516060141580611c56575080610140015151603c14155b80611c68575080610160015151604014155b15611c8557604051623dc25960e41b815260040160405180910390fd5b866040015160a001515f015161ffff16600514611cb55760405163213d071160e21b815260040160405180910390fd5b6040808801515151141580611cd4575086604001516020015151604014155b80611ce9575086604001516060015151604014155b15611d07576040516346ac673f60e01b815260040160405180910390fd5b604087015160800151602081015151905161ffff1614611d3a57604051630c6543ad60e01b815260040160405180910390fd5b604087015160a081015160200151608090910151515f9190611d5e906103f261543b565b611d6990600261543b565b611d7490600461543b565b61ffff16611d829190615455565b90506103fc8163ffffffff1611611dac57604051631350008b60e31b815260040160405180910390fd5b875180516020808301516040808501516060860151608087015160a088015160c089015185516001600160f01b0319998a169881019890985295881660228801526001600160e01b03199093166024870152908616602886015294909416602a8401526001600160801b0319909316602c8301526001600160601b031916603c82015281516030818303018152605090910190915290965080611e4e8761293a565b604051602001611e5f929190615471565b60405160208183030381529060405294508860400151935050505091939590929450565b6040805160e08082018352610101805480831b6001600160e01b03199081168552640100000000820490931b909216602080850191909152600160401b830461ffff1684860152600160501b909204608090811b6001600160801b0319908116606086015261010254821b16908401526101035460a084015261010480548551818502810185019096528086525f958695869590949360c08601939091879084015b82821015611f9c575f8481526020908190206040805160608101825260028602909201805461ffff16918301918252908252600180820154929391929184019160ff1690811115611f7857611f78614166565b6001811115611f8957611f89614166565b8152505081526020019060010190611f25565b505050508152505090505f815f01516001600160e01b03191682602001518660200151166001600160e01b0319161490505f82606001516001600160801b03191683608001518760600151166001600160801b0319161490505f8360a001518760c001511490505f846040015161ffff1688610100015161ffff161490505f5f8660c001515190505f5b81811015612081575f8860c00151828151811061204557612045614510565b602002602001015190508b610120015161ffff16815f01515f015161ffff16116120785760200151985060019250612081565b50600101612026565b5085801561208c5750845b80156120955750835b801561209e5750825b80156120a75750815b985050505050505050915091565b6040810151515f908190815b8181101561215e575f856040015182815181106120e0576120e0614510565b602002602001015190505f815f0151886040015160400151101590505f61211389604001516060015184602001516129e4565b905081801561211f5750805b1561215057604083015195505f600687600781111561214057612140614166565b14159750611b8595505050505050565b5050508060010190506120c1565b50600195600795509350505050565b80515f9081808080805b8581101561245c5761218761346d565b612192600188615485565b82036121b9578882815181106121aa576121aa614510565b60200260200101519050612300565b886121c5836001615498565b815181106121d5576121d5614510565b602002602001015190506002876121ec9190615485565b82036122645760015f5260ff60205288517ff806280aa4dfe145596c627f696302876be30d4ea721e7e2b62aecde7954710a908a908490811061223157612231614510565b60200260200101516040015160405161224a91906150c2565b9081526040519081900360200190205460ff1695506122f4565b88828151811061227657612276614510565b602002602001015160c00151156122f4575f805260ff60205288517f03d616f3758432b4d7452e2e9011612152589bfc903ce751686613c478b2af5f908a90849081106122c5576122c5614510565b6020026020010151604001516040516122de91906150c2565b9081526040519081900360200190205460ff1695505b8515612300575061245c565b88828151811061231257612312614510565b60200260200101515f015142118015612347575088828151811061233857612338614510565b60200260200101516020015142105b945084612354575061245c565b60fb5489516001600160a01b0390911690639a657054908b908590811061237d5761237d614510565b6020026020010151606001518b858151811061239b5761239b614510565b602002602001015160a0015184608001516040518463ffffffff1660e01b81526004016123ca939291906154ab565b602060405180830381865afa1580156123e5573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061240991906154e3565b935083612416575061245c565b608081015180516020909101207f7608d283b771a4ac5883dc1434c968f10814a43099a71647d6d3041b8fc57b8d0161245357600192505061245c565b50600101612177565b50831580156124685750825b80156124715750815b801561247a5750805b979650505050505050565b6101608101515f90819061249b90826020612a67565b6124a4906154fe565b90505f84602001518560800151602001516040516020016124c6929190615471565b60405160208183030381529060405290505f6002826040516124e891906150c2565b602060405180830381855afa158015612503573d5f5f3e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061252691906153b1565b90508281148015612670575f61253f886040015161293a565b90505f60fb5f9054906101000a90046001600160a01b03166001600160a01b0316639a657054838b606001518e6040518463ffffffff1660e01b815260040161258a939291906154ab565b602060405180830381865afa1580156125a5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125c991906154e3565b90505f60fb5f9054906101000a90046001600160a01b03166001600160a01b0316639a6570548c8c5f01518d602001516040518463ffffffff1660e01b8152600401612617939291906154ab565b602060405180830381865afa158015612632573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061265691906154e3565b90508180156126625750805b975050505050505050612678565b5f9450505050505b949350505050565b5f8082600781111561269457612694614166565b14806126b1575060018260078111156126af576126af614166565b145b806126cd575060028260078111156126cb576126cb614166565b145b806126e9575060048260078111156126e7576126e7614166565b145b806127055750600582600781111561270357612703614166565b145b92915050565b5f54610100900460ff16610b015760405162461bcd60e51b8152600401610790906153f0565b6001600160a01b0381163b61279e5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610790565b5f5160206158f75f395f51905f5280546001600160a01b0319166001600160a01b0392909216919091179055565b6127d583612afb565b5f825111806127e15750805b1561195b576108388383612b3a565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f61284a6135b0565b6103fc84511161285c575f9150611b85565b5f61287361286e866101b06004612a67565b612b66565b9050806101b486516128859190615485565b14612893575f925050611b85565b5f6128a086826030612a67565b90505f5f6128ad83612c29565b91509150816128c2575f955050505050611b85565b5f806128da6128d48b6101b489612a67565b8a612ddb565b91509150816128f1575f9750505050505050611b85565b5f6129008b6030610180612a67565b90505f61290c82612f58565b6040805160608101825296875260208701919091528501929092525060019a92995091975050505050505050565b60605f600883610100015161ffff16901b600884610100015161ffff16901c1790505f600884610120015161ffff16901b600885610120015161ffff16901c179050835f015184602001518560400151866060015187608001518860a001518960c001518a60e0015189898d61014001518e61016001516040516020016129cc9c9b9a99989796959493929190615521565b60405160208183030381529060405292505050919050565b5f601083511415806129f857506010825114155b15612a0457505f612705565b5f5b6010811015612a5d57828181518110612a2157612a21614510565b602002602001015160ff16848281518110612a3e57612a3e614510565b60200260200101511015612a55575f915050612705565b600101612a06565b5060019392505050565b8251606090612a768385615498565b1115612a95576040516343733a0960e11b815260040160405180910390fd5b5f826001600160401b03811115612aae57612aae6138fe565b6040519080825280601f01601f191660200182016040528015612ad8576020820181803683370190505b50905060208082019086860101612af08282876130b6565b509095945050505050565b612b0481612731565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b6060612b5f8383604051806060016040528060278152602001615917602791396130bf565b9392505050565b80515f90815b81811015612c22575f848281518110612b8757612b87614510565b016020015160f81c90505f612b9d6010836155ce565b90505f612bab6010846155e1565b90505f612bb9856002614143565b612bc49060106156d7565b612bce9083614143565b9050612bdb856002614143565b612be6906001615498565b612bf19060106156d7565b612bfb9084614143565b612c059082615498565b9050612c118188615498565b965050505050806001019050612b6c565b5050919050565b5f612c326134b6565b5f612c3f84826002612a67565b612c48906156e2565b90506001600160f01b03198116600360f81b14612c68575f925050915091565b5f612c7585600280612a67565b612c7e906156e2565b90506001600160f01b03198116600160f91b14612c9f575f93505050915091565b5f612cac86600480612a67565b612cb59061571c565b90506001600160e01b0319811615612cd2575f9450505050915091565b5f612ce087600c6010612a67565b612ce990615756565b90506001600160801b031981166f939a7233f79c4ca9940a0db3957f060760801b14612d1b575f955050505050915091565b6040805160e0810182526001600160f01b03198087168252851660208201526001600160e01b031984169181019190915260608101612d5d8960086002612a67565b612d66906156e2565b6001600160f01b0319168152602001612d8289600a6002612a67565b612d8b906156e2565b6001600160f01b03191681526001600160801b031983166020820152604001612db789601c6014612a67565b612dc090615790565b6001600160601b031916905260019890975095505050505050565b5f612de4613556565b604080518082019091525f815260606020820152612e0961286e866102406002612a67565b61ffff16808252612e1f90869061024290612a67565b602082015280515f90612e349061024261543b565b61ffff169050612e426135dd565b612e5161286e88846002612a67565b61ffff1680825260011180612e6d57506005815f015161ffff16115b15612e7d575f9450505050611b85565b612e88600283615498565b9150612e9961286e88846004612a67565b63ffffffff166020820152612eaf600483615498565b91505f612ed183836020015163ffffffff168a612a679092919063ffffffff16565b9050612edd8188613133565b604080840191909152612ef39089905f90612a67565b8552612f0188604080612a67565b60208601525f612f15896080610180612a67565b9050612f2081612f58565b604080880191909152612f38908a9061020090612a67565b6060870152505060808401929092525060a0820152600191509250929050565b612f606134f1565b612f6c825f6010612a67565b612f7590615756565b6001600160801b0319168152612f8e8260106004612a67565b612f979061571c565b6001600160e01b0319166020820152612fb3826014601c612a67565b612fbc906157ca565b63ffffffff19166040820152612fd58260306010612a67565b612fde90615756565b6001600160801b0319166060820152612ffa8260406020612a67565b613003906154fe565b60808201526130158260606020612a67565b61301e906154fe565b60a08201526130308260806020612a67565b613039906154fe565b60c082015261304b8260a06060612a67565b60e082015261306161286e836101006002612a67565b61ffff1661010082015261307c61286e836101026002612a67565b61ffff1661012082015261309482610104603c612a67565b610140808301919091526130ab9083906040612a67565b610160820152919050565b8082845e505050565b60605f5f856001600160a01b0316856040516130db91906150c2565b5f60405180830381855af49150503d805f8114613113576040519150601f19603f3d011682016040523d82523d5f602084013e613118565b606091505b5091509150613129868383876132d0565b9695505050505050565b61313b6135f7565b604051635b732b7d60e11b815282906060905f9081906001600160a01b0385169063b6e656fa90613173908a906003906004016157fe565b5f60405180830381865afa15801561318d573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526131b4919081019061581f565b91509150816131d657604051636237e47b60e11b815260040160405180910390fd5b6040805160038082526080820190925290816020015b6131f461346d565b8152602001906001900390816131ec5790505092505f5b600381101561325b5761323682828151811061322957613229614510565b6020026020010151613348565b82828151811061324857613248614510565b602090810291909101015260010161320b565b506040518060600160405280825f8151811061327957613279614510565b602002602001015181526020018260018151811061329957613299614510565b60200260200101518152602001826002815181106132b9576132b9614510565b602002602001015181525094505050505092915050565b6060831561333e5782515f03613337576001600160a01b0385163b6133375760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610790565b5081612678565b6126788383613443565b60608151801561343d5760038160021c026003821661337d5783820151613d3d18601e81901a1560ff90911615019003613386565b60038216015f19015b60405192508083526020830181810191507ffc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc80605b527804080c1014181c2024282c3034383c4044484c5054585c6064603b526ef8fcf800fcd0d4d8dce0e4e8ecf0f4601a525b600486019550855180601f1a5160061c81601e1a5183161760061c81601d1a5183161760061c81601c1a518316178352506003820191508282106133ed575050602081016040525f8152505f6060525b50919050565b8151156134535781518083602001fd5b8060405162461bcd60e51b815260040161079091906158e4565b6040518061010001604052805f81526020015f8152602001606081526020016060815260200160608152602001606081526020015f151581526020016134b161361e565b905290565b6040805160e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e082018190526101008201839052610120820192909252610140810182905261016081019190915290565b6040518060c0016040528060608152602001606081526020016135776134f1565b8152602001606081526020016135a360405180604001604052805f61ffff168152602001606081525090565b81526020016134b16135dd565b60405180606001604052806135c36134b6565b81526020016135d06134f1565b81526020016134b1613556565b604080516060810182525f80825260208201529081016134b15b60405180606001604052806003905b60608152602001906001900390816136065790505090565b604051806060016040528060608152602001606081526020016134b1604051806080016040528060608152602001606081526020015f8152602001606081525090565b5f60208284031215613671575f5ffd5b81356001600160401b03811115613686575f5ffd5b82016101208185031215612b5f575f5ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b8215158152604060208201525f6126786040830184613698565b5f602082840312156136f0575f5ffd5b81356001600160401b03811115613705575f5ffd5b820160e08185031215612b5f575f5ffd5b80356001600160a01b038116811461372c575f5ffd5b919050565b5f5f5f60608486031215613743575f5ffd5b61374c84613716565b925061375a60208501613716565b915061376860408501613716565b90509250925092565b5f5f5f60408486031215613783575f5ffd5b8335925060208401356001600160401b0381111561379f575f5ffd5b8401601f810186136137af575f5ffd5b80356001600160401b038111156137c4575f5ffd5b8660208260051b84010111156137d8575f5ffd5b939660209190910195509293505050565b5f602082840312156137f9575f5ffd5b5035919050565b5f60208284031215613810575f5ffd5b612b5f82613716565b8015158114610a46575f5ffd5b5f5f60408385031215613837575f5ffd5b82359150602083013561384981613819565b809150509250929050565b5f5f83601f840112613864575f5ffd5b5081356001600160401b0381111561387a575f5ffd5b602083019150836020828501011115611b85575f5ffd5b5f5f5f604084860312156138a3575f5ffd5b83356001600160401b038111156138b8575f5ffd5b6138c486828701613854565b90945092505060208401356001600160401b038111156138e2575f5ffd5b8401606081870312156138f3575f5ffd5b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b60405161018081016001600160401b0381118282101715613935576139356138fe565b60405290565b604051606081016001600160401b0381118282101715613935576139356138fe565b60405160c081016001600160401b0381118282101715613935576139356138fe565b60405160e081016001600160401b0381118282101715613935576139356138fe565b604051608081016001600160401b0381118282101715613935576139356138fe565b60405161010081016001600160401b0381118282101715613935576139356138fe565b604051601f8201601f191681016001600160401b0381118282101715613a0e57613a0e6138fe565b604052919050565b5f6001600160401b03821115613a2e57613a2e6138fe565b50601f01601f191660200190565b5f613a4e613a4984613a16565b6139e6565b9050828152838383011115613a61575f5ffd5b828260208301375f602084830101529392505050565b5f60208284031215613a87575f5ffd5b81356001600160401b03811115613a9c575f5ffd5b8201601f81018413613aac575f5ffd5b61267884823560208401613a3c565b604081525f613acd6040830185613698565b8281036020840152613adf8185613698565b95945050505050565b5f82601f830112613af7575f5ffd5b612b5f83833560208501613a3c565b5f5f60408385031215613b17575f5ffd5b613b2083613716565b915060208301356001600160401b03811115613b3a575f5ffd5b613b4685828601613ae8565b9150509250929050565b5f5f60208385031215613b61575f5ffd5b82356001600160401b03811115613b76575f5ffd5b613b8285828601613854565b90969095509350505050565b5f5f60408385031215613b9f575f5ffd5b8235915060208301356001600160401b03811115613b3a575f5ffd5b80356001600160f01b03198116811461372c575f5ffd5b6001600160e01b031981168114610a46575f5ffd5b803561372c81613bd2565b6001600160801b031981168114610a46575f5ffd5b803561372c81613bf2565b803563ffffffff198116811461372c575f5ffd5b61ffff81168114610a46575f5ffd5b803561372c81613c26565b5f6101808284031215613c51575f5ffd5b613c59613912565b9050613c6482613c07565b8152613c7260208301613be7565b6020820152613c8360408301613c12565b6040820152613c9460608301613c07565b60608201526080828101359082015260a0808301359082015260c0808301359082015260e08201356001600160401b03811115613ccf575f5ffd5b613cdb84828501613ae8565b60e083015250613cee6101008301613c35565b610100820152613d016101208301613c35565b6101208201526101408201356001600160401b03811115613d20575f5ffd5b613d2c84828501613ae8565b610140830152506101608201356001600160401b03811115613d4c575f5ffd5b613d5884828501613ae8565b6101608301525092915050565b5f60408284031215613d75575f5ffd5b604080519081016001600160401b0381118282101715613d9757613d976138fe565b6040529050808235613da881613c26565b815260208301356001600160401b03811115613dc2575f5ffd5b613dce85828601613ae8565b6020830152505092915050565b5f60608284031215613deb575f5ffd5b613df361393b565b90508135613e0081613c26565b8152602082013563ffffffff81168114613e18575f5ffd5b602082015260408201356001600160401b03811115613e35575f5ffd5b8201601f81018413613e45575f5ffd5b613e4d61393b565b806060830186811115613e5e575f5ffd5b835b81811015613e985780356001600160401b03811115613e7d575f5ffd5b613e8989828801613ae8565b85525060209384019301613e60565b5050604084015250909392505050565b5f60c08284031215613eb8575f5ffd5b613ec061395d565b905081356001600160401b03811115613ed7575f5ffd5b613ee384828501613ae8565b82525060208201356001600160401b03811115613efe575f5ffd5b613f0a84828501613ae8565b60208301525060408201356001600160401b03811115613f28575f5ffd5b613f3484828501613c40565b60408301525060608201356001600160401b03811115613f52575f5ffd5b613f5e84828501613ae8565b60608301525060808201356001600160401b03811115613f7c575f5ffd5b613f8884828501613d65565b60808301525060a08201356001600160401b03811115613fa6575f5ffd5b613fb284828501613ddb565b60a08301525092915050565b5f813603610120811215613fd0575f5ffd5b613fd861393b565b60e0821215613fe5575f5ffd5b613fed61397f565b9150613ff884613bbb565b825261400660208501613bbb565b6020830152604084013561401981613bd2565b604083015261402a60608501613bbb565b606083015261403b60808501613bbb565b608083015260a084013561404e81613bf2565b60a083015260c08401356001600160601b03198116811461406d575f5ffd5b60c083015290815260e0830135906001600160401b0382111561408e575f5ffd5b61409a36838601613c40565b602082015261010084013591506001600160401b038211156140ba575f5ffd5b6140c636838601613ea8565b60408201529392505050565b5f813561270581613c26565b5f813561270581613bf2565b5f5f8335601e198436030181126140ff575f5ffd5b8301803591506001600160401b03821115614118575f5ffd5b6020019150600681901b3603821315611b85575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176127055761270561412f565b60028110610a46575f5ffd5b634e487b7160e01b5f52602160045260245ffd5b813561418581613c26565b61ffff811661ffff19835416178255506001810160208301356141a78161415a565b600281106141b7576141b7614166565b60ff1982541660ff8216811783555050505050565b600160401b8311156141e0576141e06138fe565b805483825580841015614252576001600160ff1b03811681146142055761420561412f565b6001600160ff1b038416841461421d5761421d61412f565b815f5260205f208160011b81018560011b820191505b8082101561424f575f82555f6001830155600282019150614233565b50505b505f8181526020812083915b8581101561428657614270838361417a565b604092909201916002919091019060010161425e565b505050505050565b813561429981613bd2565b8060e01c63ffffffff198354161782555060208201356142b881613bd2565b815467ffffffff00000000191660c09190911c67ffffffff000000001617815561430d6142e7604084016140d2565b825469ffff0000000000000000191660409190911b69ffff000000000000000016178255565b61435861431c606084016140de565b8280546fffffffffffffffffffffffffffffffff60501b191660309290921c6fffffffffffffffffffffffffffffffff60501b16919091179055565b614382614367608084016140de565b600183018160801c6001600160801b03198254161781555050565b60a0820135600282015561439960c08301836140ea565b6108388183600386016141cc565b5f5f8335601e198436030181126143bc575f5ffd5b83016020810192503590506001600160401b038111156143da575f5ffd5b8060061b3603821315611b85575f5ffd5b8183526020830192505f815f5b8481101561444757813561440b81613c26565b61ffff168652602082013561441f8161415a565b6002811061442f5761442f614166565b602087015260409586019591909101906001016143f8565b5093949350505050565b602081525f823561446181613bd2565b6001600160e01b03191660208381019190915283013561448081613bd2565b63ffffffff60e01b811660408401525061449c60408401613c35565b61ffff81166060840152506144b360608401613c07565b6001600160801b031981166080840152506144d060808401613c07565b6001600160801b0319811660a08401525060a083013560c0838101919091526144fb908401846143a7565b60e080850152613adf610100850182846143eb565b634e487b7160e01b5f52603260045260245ffd5b5f5f8335601e19843603018112614539575f5ffd5b8301803591506001600160401b03821115614552575f5ffd5b602001915036819003821315611b85575f5ffd5b818382375f9101908152919050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b602081525f612678602083018486614575565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600181811c9082168061465c57607f821691505b60208210810361343d57634e487b7160e01b5f52602260045260245ffd5b5b81811015610d77575f815560010161467b565b601f82111561195b57805f5260205f20601f840160051c810160208510156146b35750805b610963601f850160051c83018261467a565b6001600160401b038311156146dc576146dc6138fe565b6146f0836146ea8354614648565b8361468e565b5f601f841160018114614721575f851561470a5750838201355b5f19600387901b1c1916600186901b178355610963565b5f83815260208120601f198716915b828110156147505786850135825560209485019460019092019101614730565b508682101561476c575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b5f5f8335601e19843603018112614793575f5ffd5b8301803591506001600160401b038211156147ac575f5ffd5b6020019150600581901b3603821315611b85575f5ffd5b5f8235605e198336030181126147d7575f5ffd5b9190910192915050565b80545f82558015610d7757815f5260205f2061195b601f830160051c82018261467a565b600160401b821115614819576148196138fe565b80548282558083101561195b57815f5260205f20601f840160051c8101601f85168015614855575f19820180545f198360200360031b1c168155505b50610963601f840160051c83018261467a565b60ff81168114610a46575f5ffd5b5f813561270581614868565b60088110610a46575f5ffd5b5f813561270581614882565b600882106148aa576148aa614166565b60ff1981541660ff831681178255505050565b81358155600181016148d2602084018461477e565b6001600160401b038111156148e9576148e96138fe565b6148f38184614805565b5f8381526020902092508060051c5f5b81811015614958575f5f5b602081101561494b5761493a61492387614876565b60ff908116600384901b90811b91901b1984161790565b60209690960195915060010161490e565b5085820155600101614903565b50601f198216808303818414614996575f5f5b828110156149905761497f61492388614876565b60209790970196915060010161496b565b50868401555b505050505050610d776149ab6040840161488e565b6002830161489a565b600160401b8311156149c8576149c86138fe565b805483825580841015614a3757806003026003810482146149eb576149eb61412f565b84600302600381048614614a0157614a0161412f565b5f8481526020902091820191015b81811015614a34575f8155614a26600182016147e1565b5f6002820155600301614a0f565b50505b505f8181526020812083915b8581101561428657614a5e614a5884876147c3565b836148bd565b6020929092019160039190910190600101614a43565b614a7e8283614524565b6001600160401b03811115614a9557614a956138fe565b614aa981614aa38554614648565b8561468e565b5f601f821160018114614ada575f8315614ac35750838201355b5f19600385901b1c1916600184901b178555614b31565b5f85815260208120601f198516915b82811015614b095786850135825560209485019460019092019101614ae9565b5084821015614b25575f1960f88660031b161c19848701351681555b505060018360011b0185555b50505050614b426020830183614524565b614b508183600186016146c5565b5050614b5f604083018361477e565b6108388183600286016149b4565b5f5f8335601e19843603018112614b82575f5ffd5b83016020810192503590506001600160401b03811115614ba0575f5ffd5b803603821315611b85575f5ffd5b5f5f8335601e19843603018112614bc3575f5ffd5b83016020810192503590506001600160401b03811115614be1575f5ffd5b8060051b3603821315611b85575f5ffd5b602081525f614c018384614b6d565b60606020850152614c16608085018284614575565b915050614c266020850185614b6d565b848303601f19016040860152614c3d838284614575565b92505050614c4e6040850185614bae565b848303601f19016060860152808352602080840190600583901b850101835f36829003605e19015b85821015614d2e57878403601f190185528235818112614c94575f5ffd5b87018035855260608501614cab6020830183614bae565b6060602089015291829052905f90608088015b81831015614ce9578335614cd181614868565b60ff1681526020938401936001939093019201614cbe565b60408501359450614cf985614882565b60088510614d0957614d09614166565b8460408a01528098505050505050602083019250602085019450600182019150614c76565b50919998505050505050505050565b604081525f614d4f6040830185613698565b905082151560208301529392505050565b805161372c81613819565b5f82601f830112614d7a575f5ffd5b8151602083015f614d8d613a4984613a16565b9050828152858383011115614da0575f5ffd5b8282602083015e5f92810160200192909252509392505050565b5f6001600160401b03821115614dd257614dd26138fe565b5060051b60200190565b5f60608284031215614dec575f5ffd5b614df461393b565b905081516001600160401b03811115614e0b575f5ffd5b614e1784828501614d6b565b82525060208201516001600160401b03811115614e32575f5ffd5b614e3e84828501614d6b565b60208301525060408201516001600160401b03811115614e5c575f5ffd5b820160808185031215614e6d575f5ffd5b614e756139a1565b81516001600160401b03811115614e8a575f5ffd5b614e9686828501614d6b565b82525060208201516001600160401b03811115614eb1575f5ffd5b614ebd86828501614d6b565b6020830152506040828101519082015260608201516001600160401b03811115614ee5575f5ffd5b80830192505084601f830112614ef9575f5ffd5b8151614f07613a4982614dba565b8082825260208201915060208360051b860101925087831115614f28575f5ffd5b6020850194505b82851015614f4a578451825260209485019490910190614f2f565b6060840152505060408301525092915050565b5f5f60408385031215614f6e575f5ffd5b8251614f7981613819565b60208401519092506001600160401b03811115614f94575f5ffd5b83016101008186031215614fa6575f5ffd5b614fae6139c3565b815181526020808301519082015260408201516001600160401b03811115614fd4575f5ffd5b614fe087828501614d6b565b60408301525060608201516001600160401b03811115614ffe575f5ffd5b61500a87828501614d6b565b60608301525060808201516001600160401b03811115615028575f5ffd5b61503487828501614d6b565b60808301525060a08201516001600160401b03811115615052575f5ffd5b61505e87828501614d6b565b60a08301525061507060c08301614d60565b60c082015260e08201516001600160401b0381111561508d575f5ffd5b61509987828501614ddc565b60e08301525080925050509250929050565b5f81518060208401855e5f93019283525090919050565b5f612b5f82846150ab565b80516001600160801b03191682525f60208201516150f760208501826001600160e01b0319169052565b506040820151615110604085018263ffffffff19169052565b50606082015161512c60608501826001600160801b0319169052565b506080820151608084015260a082015160a084015260c082015160c084015260e082015161018060e0850152615166610180850182613698565b905061010083015161517f61010086018261ffff169052565b5061012083015161519761012086018261ffff169052565b506101408301518482036101408601526151b18282613698565b915050610160830151848203610160860152613adf8282613698565b5f6060830161ffff835116845263ffffffff60208401511660208501526040830151606060408601528182905060c0860192505f5b600381101561523457605f1987850301825261521f848451613698565b93506020928301929190910190600101615202565b509195945050505050565b5f815160c0845261525360c0850182613698565b90506020830151848203602086015261526c8282613698565b9150506040830151848203604086015261528682826150cd565b915050606083015184820360608601526152a08282613698565b9150506080830151848203608086015261ffff815116825260208101519050604060208301526152d36040830182613698565b91505060a083015184820360a0860152613adf82826151cd565b602081525f825161ffff60f01b815116602084015261ffff60f01b602082015116604084015263ffffffff60e01b604082015116606084015261ffff60f01b606082015116608084015261ffff60f01b60808201511660a084015260a081015161536360c08501826001600160801b0319169052565b5060c001516001600160601b03191660e083015260208301516101206101008401526153936101408401826150cd565b90506040840151601f1984830301610120850152613adf828261523f565b5f602082840312156153c1575f5ffd5b5051919050565b8281525f600883106153dc576153dc614166565b5060f89190911b6020820152602101919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b61ffff81811683821601908111156127055761270561412f565b63ffffffff81811683821601908111156127055761270561412f565b5f61267861547f83866150ab565b846150ab565b818103818111156127055761270561412f565b808201808211156127055761270561412f565b606081525f6154bd6060830186613698565b82810360208401526154cf8186613698565b905082810360408401526131298185613698565b5f602082840312156154f3575f5ffd5b8151612b5f81613819565b8051602080830151919081101561343d575f1960209190910360031b1b16919050565b6001600160801b03198d811682526001600160e01b03198d16601083015263ffffffff198c1660148301528a1660308201526040810189905260608101889052608081018790525f61557660a08301886150ab565b6001600160f01b031960f088811b8216835287901b1660028201526155a76155a160048301876150ab565b856150ab565b9f9e505050505050505050505050505050565b634e487b7160e01b5f52601260045260245ffd5b5f826155dc576155dc6155ba565b500490565b5f826155ef576155ef6155ba565b500690565b6001815b600184111561562f578085048111156156135761561361412f565b600184161561562157908102905b60019390931c9280026155f8565b935093915050565b5f8261564557506001612705565b8161565157505f612705565b816001811461566757600281146156715761568d565b6001915050612705565b60ff8411156156825761568261412f565b50506001821b612705565b5060208310610133831016604e8410600b84101617156156b0575081810a612705565b6156bc5f1984846155f4565b805f19048211156156cf576156cf61412f565b029392505050565b5f612b5f8383615637565b805160208201516001600160f01b0319811691906002821015612c22576001600160f01b031960029290920360031b82901b161692915050565b805160208201516001600160e01b0319811691906004821015612c22576001600160e01b031960049290920360031b82901b161692915050565b805160208201516001600160801b0319811691906010821015612c22576001600160801b031960109290920360031b82901b161692915050565b805160208201516001600160601b0319811691906014821015612c22576001600160601b031960149290920360031b82901b161692915050565b8051602082015163ffffffff1981169190601c821015612c225763ffffffff19601c9290920360031b82901b161692915050565b604081525f6158106040830185613698565b90508260208301529392505050565b5f5f60408385031215615830575f5ffd5b825161583b81613819565b60208401519092506001600160401b03811115615856575f5ffd5b8301601f81018513615866575f5ffd5b8051615874613a4982614dba565b8082825260208201915060208360051b850101925087831115615895575f5ffd5b602084015b838110156158d55780516001600160401b038111156158b7575f5ffd5b6158c68a602083890101614d6b565b8452506020928301920161589a565b50809450505050509250929050565b602081525f612b5f602083018461369856fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122020c9aee297253a1c57d6d5d86853a955f3d1d76f0c7a7f66c872a18af583810f64736f6c634300081e0033
Deployed ByteCode
0x6080604052600436106101db575f3560e01c806352d1902d116100fd5780638456cb5911610092578063cf12f55511610062578063cf12f555146105e5578063e2e282941461062f578063e30c39781461064e578063f2fde38b1461066b575f5ffd5b80638456cb59146105055780638abf6077146105195780638da5cb5b1461052d578063b684252f1461054a575f5ffd5b8063715018a6116100cd578063715018a6146104aa578063769d87e7146104be57806379ba5097146104dd57806383801580146104f1575f5ffd5b806352d1902d1461041b57806354e219131461043d5780635c975abb1461046b578063610de4801461048b575f5ffd5b80633075db56116101735780633f4ba83a116101435780633f4ba83a146103a85780634bc7eea4146103bc5780634c0977a9146103db5780634f1ef28614610408575f5ffd5b80633075db561461032857806332f555ec1461033c5780633659cfe61461036a5780633a34301414610389575f5ffd5b80630d23d71b116101ae5780630d23d71b146102aa578063123ac29e146102c9578063184b9559146102ea5780631f3be09614610309575f5ffd5b806301d711f4146101df57806304f3bcec1461021b5780630570e1fc1461024d578063089a168f1461027d575b5f5ffd5b3480156101ea575f5ffd5b5060fc546101fe906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610226575f5ffd5b507f00000000000000000000000000000000000000000000000000000000000000006101fe565b348015610258575f5ffd5b5060fc5461026d90600160a01b900460ff1681565b6040519015158152602001610212565b348015610288575f5ffd5b5061029c610297366004613661565b61068a565b6040516102129291906136c6565b3480156102b5575f5ffd5b5060fb546101fe906001600160a01b031681565b3480156102d4575f5ffd5b506102e86102e33660046136e0565b6106a7565b005b3480156102f5575f5ffd5b506102e8610304366004613731565b6106fa565b348015610314575f5ffd5b506102e8610323366004613771565b61083e565b348015610333575f5ffd5b5061026d61096a565b348015610347575f5ffd5b5061026d6103563660046137e9565b60fe6020525f908152604090205460ff1681565b348015610375575f5ffd5b506102e8610384366004613800565b610982565b348015610394575f5ffd5b506102e86103a3366004613826565b610a49565b3480156103b3575f5ffd5b506102e8610aa8565b3480156103c7575f5ffd5b506102e86103d6366004613891565b610b03565b3480156103e6575f5ffd5b506103fa6103f5366004613a77565b610b8e565b604051610212929190613abb565b6102e8610416366004613b06565b610cc2565b348015610426575f5ffd5b5061042f610d7b565b604051908152602001610212565b348015610448575f5ffd5b5061026d6104573660046137e9565b60fd6020525f908152604090205460ff1681565b348015610476575f5ffd5b5061026d60c954610100900460ff1660021490565b348015610496575f5ffd5b506102e86104a5366004613771565b610e2c565b3480156104b5575f5ffd5b506102e8610f5c565b3480156104c9575f5ffd5b5061026d6104d8366004613b50565b610f6d565b3480156104e8575f5ffd5b506102e8610f80565b3480156104fc575f5ffd5b506102e8610ff7565b348015610510575f5ffd5b506102e8611065565b348015610524575f5ffd5b506101fe6110ba565b348015610538575f5ffd5b506033546001600160a01b03166101fe565b348015610555575f5ffd5b506101015461010254610103546105979260e081811b93640100000000830490911b9261ffff600160401b84041692600160501b9004608090811b92901b9086565b604080516001600160e01b0319978816815296909516602087015261ffff909316938501939093526001600160801b03199081166060850152909116608083015260a082015260c001610212565b3480156105f0575f5ffd5b5061026d6105ff366004613b8e565b60ff60208181525f9384526040909320825180840185018051928152908501939094019290922091909252541681565b34801561063a575f5ffd5b506102e8610649366004613826565b6110c8565b348015610659575f5ffd5b506065546001600160a01b03166101fe565b348015610676575f5ffd5b506102e8610685366004613800565b61111f565b5f606061069e61069984613fbe565b611190565b91509150915091565b6106af61184d565b806101016106bd828261428e565b9050507f8867fcb26463d2f77f8c8f24316221d64d8b4821bf4dea1b4c9b83d4ba271c45816040516106ef9190614451565b60405180910390a150565b5f54610100900460ff161580801561071857505f54600160ff909116105b806107315750303b15801561073157505f5460ff166001145b6107995760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b5f805460ff1916600117905580156107ba575f805461ff0019166101001790555b6107c3846118a7565b60fb80546001600160a01b038086166001600160a01b03199283161790925560fc8054928516929091169190911790558015610838575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b61084661184d565b805f5b81811015610963575f85815260ff6020526040902084848381811061087057610870614510565b90506020028101906108829190614524565b604051610890929190614566565b9081526040519081900360200190205460ff161561095b575f85815260ff602052604090208484838181106108c7576108c7614510565b90506020028101906108d99190614524565b6040516108e7929190614566565b908152604051908190036020019020805460ff19169055847fee365795c95effb059e7128967d8e0dce7b2eaaf750bb4c422df5411fb8aedfd85858481811061093257610932614510565b90506020028101906109449190614524565b60405161095292919061459d565b60405180910390a25b600101610849565b5050505050565b5f600261097960c95460ff1690565b60ff1614905090565b6001600160a01b037f000000000000000000000000c51aac3cff330586435cf2168fad9e5f3c1a86541630036109ca5760405162461bcd60e51b8152600401610790906145b0565b7f000000000000000000000000c51aac3cff330586435cf2168fad9e5f3c1a86546001600160a01b03166109fc611905565b6001600160a01b031614610a225760405162461bcd60e51b8152600401610790906145fc565b610a2b81611920565b604080515f80825260208201909252610a4691839190611928565b50565b610a5161184d565b5f82815260fd6020908152604091829020805460ff1916841515908117909155915191825283917fe9c8da9c89154486636f96dbbf87f6cdf819637dda597383e5b1533b446b51d291015b60405180910390a25050565b610ab0611a97565b610ac460c9805461ff001916610100179055565b6040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa9060200160405180910390a1610b01335f611ac8565b565b610b0b61184d565b806101008484604051610b1f929190614566565b908152604051908190036020019020610b388282614a74565b5050604051610b4a9084908490614566565b60405180910390207f540fc9dd1a61f44f6860558982bac073b37667cb331897eb59633910cfd0382282604051610b819190614bf2565b60405180910390a2505050565b805160208183018101805161010082529282019190930120915280548190610bb590614648565b80601f0160208091040260200160405190810160405280929190818152602001828054610be190614648565b8015610c2c5780601f10610c0357610100808354040283529160200191610c2c565b820191905f5260205f20905b815481529060010190602001808311610c0f57829003601f168201915b505050505090806001018054610c4190614648565b80601f0160208091040260200160405190810160405280929190818152602001828054610c6d90614648565b8015610cb85780601f10610c8f57610100808354040283529160200191610cb8565b820191905f5260205f20905b815481529060010190602001808311610c9b57829003601f168201915b5050505050905082565b6001600160a01b037f000000000000000000000000c51aac3cff330586435cf2168fad9e5f3c1a8654163003610d0a5760405162461bcd60e51b8152600401610790906145b0565b7f000000000000000000000000c51aac3cff330586435cf2168fad9e5f3c1a86546001600160a01b0316610d3c611905565b6001600160a01b031614610d625760405162461bcd60e51b8152600401610790906145fc565b610d6b82611920565b610d7782826001611928565b5050565b5f306001600160a01b037f000000000000000000000000c51aac3cff330586435cf2168fad9e5f3c1a86541614610e1a5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610790565b505f5160206158f75f395f51905f5290565b610e3461184d565b805f5b81811015610963575f85815260ff60205260409020848483818110610e5e57610e5e614510565b9050602002810190610e709190614524565b604051610e7e929190614566565b9081526040519081900360200190205460ff16610f54575f85815260ff60205260409020600190858584818110610eb757610eb7614510565b9050602002810190610ec99190614524565b604051610ed7929190614566565b908152604051908190036020019020805491151560ff19909216919091179055847f775b5995b6d311d1ac0f46050a5a41564043b346e952189284ec57bd4c0d58dd858584818110610f2b57610f2b614510565b9050602002810190610f3d9190614524565b604051610f4b92919061459d565b60405180910390a25b600101610e37565b610f6461184d565b610b015f611ad0565b5f610f788383611ae9565b509392505050565b60655433906001600160a01b03168114610fee5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610790565b610a4681611ad0565b610fff61184d565b60fc805460ff600160a01b808304821615810260ff60a01b1990931692909217928390556040517fcafd71daf69ac558b30d115a7b5a9751259ac2352764cdf5b7038c74dc43ccb49361105b9390049091161515815260200190565b60405180910390a1565b61106d611b8c565b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200160405180910390a1610b01336001611ac8565b5f6110c3611905565b905090565b6110d061184d565b5f82815260fe6020908152604091829020805460ff1916841515908117909155915191825283917fa8796d5584281f38b5f5c7f2ff1ee978acc17db51930ab666a66712c2d9f93ac9101610a9c565b61112761184d565b606580546001600160a01b0383166001600160a01b031990911681179091556111586033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b604080516001600160f81b031960208201528151600181830301815260219091019091525f906060908280806111c587611bbe565b9450945050509250826111e057505f96929550919350505050565b60fc54600160a01b900460ff16156112475760208088018051608001515f90815260fd8352604080822054925160c00151825260fe909352919091205460ff918216911681158061122f575080155b1561124457505f989497509395505050505050565b50505b5f5f61125a896040015160400151611e83565b925090508061127357505f989497509395505050505050565b8015806112915750600182600181111561128f5761128f614166565b145b156112a657505f989497509395505050505050565b5060606112cd60405180606001604052806060815260200160608152602001606081525090565b6040805160038082526080820190925290816020015b6112eb61346d565b8152602001906001900390816112e35790505091505f5b60038110156113e55760fc5460a0860151604001518215915f916001600160a01b039091169063c1c1d5c190856003811061133f5761133f614510565b6020020151846040518363ffffffff1660e01b8152600401611362929190614d3d565b5f60405180830381865afa15801561137c573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526113a39190810190614f5d565b8685815181106113b5576113b5614510565b60209081029190910101529050806113db57505f9c989b50979950505050505050505050565b5050600101611302565b505f825f815181106113f9576113f9614510565b602002602001015160e00151604001516020015190506101008160405161142091906150c2565b90815260200160405180910390206040518060600160405290815f8201805461144890614648565b80601f016020809104026020016040519081016040528092919081815260200182805461147490614648565b80156114bf5780601f10611496576101008083540402835291602001916114bf565b820191905f5260205f20905b8154815290600101906020018083116114a257829003601f168201915b505050505081526020016001820180546114d890614648565b80601f016020809104026020016040519081016040528092919081815260200182805461150490614648565b801561154f5780601f106115265761010080835404028352916020019161154f565b820191905f5260205f20905b81548152906001019060200180831161153257829003601f168201915b5050505050815260200160028201805480602002602001604051908101604052809291908181526020015f905b8282101561165b578382905f5260205f2090600302016040518060600160405290815f82015481526020016001820180548060200260200160405190810160405280929190818152602001828054801561161057602002820191905f5260205f20905f905b825461010083900a900460ff168152602060019283018181049485019490930390920291018084116115e15790505b5050509183525050600282015460209091019060ff16600781111561163757611637614166565b600781111561164857611648614166565b815250508152602001906001019061157c565b50505091525050602081810151805190820120835191840191909120919350148061169357505f9b979a509698505050505050505050565b5f845f815181106116a6576116a6614510565b60209081029190910181015160e0810151604001515186518051908401208151919093012090925014806116e957505f9d999c50989a5050505050505050505050565b505050505f5f611716845f8151811061170457611704614510565b602002602001015160e00151846120b5565b925090508061173257505f9b979a509698505050505050505050565b505f61173d8461216d565b90508061175757505f9b979a509698505050505050505050565b505f61178a845f8151811061176e5761176e614510565b60200260200101516080015188888f6040015160400151612485565b9050806117a457505f9b979a509698505050505050505050565b5060028b6040516020016117b891906152ed565b60408051601f19818403018152908290526117d2916150c2565b602060405180830381855afa1580156117ed573d5f5f3e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061181091906153b1565b816040516020016118229291906153c8565b604051602081830303815290604052975061183c81612680565b9b979a509698505050505050505050565b6033546001600160a01b03163314610b015760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610790565b5f54610100900460ff166118cd5760405162461bcd60e51b8152600401610790906153f0565b6118d561270b565b6118f36001600160a01b038216156118ed5781611ad0565b33611ad0565b5060c9805461ff001916610100179055565b5f5160206158f75f395f51905f52546001600160a01b031690565b610a4661184d565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156119605761195b83612731565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156119ba575060408051601f3d908101601f191682019092526119b7918101906153b1565b60015b611a1d5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610790565b5f5160206158f75f395f51905f528114611a8b5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610790565b5061195b8383836127cc565b611aab60c954610100900460ff1660021490565b610b015760405163bae6e2a960e01b815260040160405180910390fd5b610d7761184d565b606580546001600160a01b0319169055610a46816127f0565b6040516001600160f81b031960208201525f90606090829060210160408051601f198184030181526020601f880181900481028401810190925286835292505f918291611b5d919089908990819084018382808284375f920191909152505060fc546001600160a01b031691506128419050565b9150915081611b74575f8394509450505050611b85565b611b7d81611190565b945094505050505b9250929050565b611ba060c954610100900460ff1660021490565b15610b015760405163bae6e2a960e01b815260040160405180910390fd5b5f611bc76134b6565b611bcf6134f1565b6060611bd9613556565b6020860151604080880151015160e08201515160019750919450906060141580611c0a575083610140015151603c14155b80611c1c575083610160015151604014155b15611c3a57604051633c20ffcf60e11b815260040160405180910390fd5b8060e00151516060141580611c56575080610140015151603c14155b80611c68575080610160015151604014155b15611c8557604051623dc25960e41b815260040160405180910390fd5b866040015160a001515f015161ffff16600514611cb55760405163213d071160e21b815260040160405180910390fd5b6040808801515151141580611cd4575086604001516020015151604014155b80611ce9575086604001516060015151604014155b15611d07576040516346ac673f60e01b815260040160405180910390fd5b604087015160800151602081015151905161ffff1614611d3a57604051630c6543ad60e01b815260040160405180910390fd5b604087015160a081015160200151608090910151515f9190611d5e906103f261543b565b611d6990600261543b565b611d7490600461543b565b61ffff16611d829190615455565b90506103fc8163ffffffff1611611dac57604051631350008b60e31b815260040160405180910390fd5b875180516020808301516040808501516060860151608087015160a088015160c089015185516001600160f01b0319998a169881019890985295881660228801526001600160e01b03199093166024870152908616602886015294909416602a8401526001600160801b0319909316602c8301526001600160601b031916603c82015281516030818303018152605090910190915290965080611e4e8761293a565b604051602001611e5f929190615471565b60405160208183030381529060405294508860400151935050505091939590929450565b6040805160e08082018352610101805480831b6001600160e01b03199081168552640100000000820490931b909216602080850191909152600160401b830461ffff1684860152600160501b909204608090811b6001600160801b0319908116606086015261010254821b16908401526101035460a084015261010480548551818502810185019096528086525f958695869590949360c08601939091879084015b82821015611f9c575f8481526020908190206040805160608101825260028602909201805461ffff16918301918252908252600180820154929391929184019160ff1690811115611f7857611f78614166565b6001811115611f8957611f89614166565b8152505081526020019060010190611f25565b505050508152505090505f815f01516001600160e01b03191682602001518660200151166001600160e01b0319161490505f82606001516001600160801b03191683608001518760600151166001600160801b0319161490505f8360a001518760c001511490505f846040015161ffff1688610100015161ffff161490505f5f8660c001515190505f5b81811015612081575f8860c00151828151811061204557612045614510565b602002602001015190508b610120015161ffff16815f01515f015161ffff16116120785760200151985060019250612081565b50600101612026565b5085801561208c5750845b80156120955750835b801561209e5750825b80156120a75750815b985050505050505050915091565b6040810151515f908190815b8181101561215e575f856040015182815181106120e0576120e0614510565b602002602001015190505f815f0151886040015160400151101590505f61211389604001516060015184602001516129e4565b905081801561211f5750805b1561215057604083015195505f600687600781111561214057612140614166565b14159750611b8595505050505050565b5050508060010190506120c1565b50600195600795509350505050565b80515f9081808080805b8581101561245c5761218761346d565b612192600188615485565b82036121b9578882815181106121aa576121aa614510565b60200260200101519050612300565b886121c5836001615498565b815181106121d5576121d5614510565b602002602001015190506002876121ec9190615485565b82036122645760015f5260ff60205288517ff806280aa4dfe145596c627f696302876be30d4ea721e7e2b62aecde7954710a908a908490811061223157612231614510565b60200260200101516040015160405161224a91906150c2565b9081526040519081900360200190205460ff1695506122f4565b88828151811061227657612276614510565b602002602001015160c00151156122f4575f805260ff60205288517f03d616f3758432b4d7452e2e9011612152589bfc903ce751686613c478b2af5f908a90849081106122c5576122c5614510565b6020026020010151604001516040516122de91906150c2565b9081526040519081900360200190205460ff1695505b8515612300575061245c565b88828151811061231257612312614510565b60200260200101515f015142118015612347575088828151811061233857612338614510565b60200260200101516020015142105b945084612354575061245c565b60fb5489516001600160a01b0390911690639a657054908b908590811061237d5761237d614510565b6020026020010151606001518b858151811061239b5761239b614510565b602002602001015160a0015184608001516040518463ffffffff1660e01b81526004016123ca939291906154ab565b602060405180830381865afa1580156123e5573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061240991906154e3565b935083612416575061245c565b608081015180516020909101207f7608d283b771a4ac5883dc1434c968f10814a43099a71647d6d3041b8fc57b8d0161245357600192505061245c565b50600101612177565b50831580156124685750825b80156124715750815b801561247a5750805b979650505050505050565b6101608101515f90819061249b90826020612a67565b6124a4906154fe565b90505f84602001518560800151602001516040516020016124c6929190615471565b60405160208183030381529060405290505f6002826040516124e891906150c2565b602060405180830381855afa158015612503573d5f5f3e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061252691906153b1565b90508281148015612670575f61253f886040015161293a565b90505f60fb5f9054906101000a90046001600160a01b03166001600160a01b0316639a657054838b606001518e6040518463ffffffff1660e01b815260040161258a939291906154ab565b602060405180830381865afa1580156125a5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125c991906154e3565b90505f60fb5f9054906101000a90046001600160a01b03166001600160a01b0316639a6570548c8c5f01518d602001516040518463ffffffff1660e01b8152600401612617939291906154ab565b602060405180830381865afa158015612632573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061265691906154e3565b90508180156126625750805b975050505050505050612678565b5f9450505050505b949350505050565b5f8082600781111561269457612694614166565b14806126b1575060018260078111156126af576126af614166565b145b806126cd575060028260078111156126cb576126cb614166565b145b806126e9575060048260078111156126e7576126e7614166565b145b806127055750600582600781111561270357612703614166565b145b92915050565b5f54610100900460ff16610b015760405162461bcd60e51b8152600401610790906153f0565b6001600160a01b0381163b61279e5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610790565b5f5160206158f75f395f51905f5280546001600160a01b0319166001600160a01b0392909216919091179055565b6127d583612afb565b5f825111806127e15750805b1561195b576108388383612b3a565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f61284a6135b0565b6103fc84511161285c575f9150611b85565b5f61287361286e866101b06004612a67565b612b66565b9050806101b486516128859190615485565b14612893575f925050611b85565b5f6128a086826030612a67565b90505f5f6128ad83612c29565b91509150816128c2575f955050505050611b85565b5f806128da6128d48b6101b489612a67565b8a612ddb565b91509150816128f1575f9750505050505050611b85565b5f6129008b6030610180612a67565b90505f61290c82612f58565b6040805160608101825296875260208701919091528501929092525060019a92995091975050505050505050565b60605f600883610100015161ffff16901b600884610100015161ffff16901c1790505f600884610120015161ffff16901b600885610120015161ffff16901c179050835f015184602001518560400151866060015187608001518860a001518960c001518a60e0015189898d61014001518e61016001516040516020016129cc9c9b9a99989796959493929190615521565b60405160208183030381529060405292505050919050565b5f601083511415806129f857506010825114155b15612a0457505f612705565b5f5b6010811015612a5d57828181518110612a2157612a21614510565b602002602001015160ff16848281518110612a3e57612a3e614510565b60200260200101511015612a55575f915050612705565b600101612a06565b5060019392505050565b8251606090612a768385615498565b1115612a95576040516343733a0960e11b815260040160405180910390fd5b5f826001600160401b03811115612aae57612aae6138fe565b6040519080825280601f01601f191660200182016040528015612ad8576020820181803683370190505b50905060208082019086860101612af08282876130b6565b509095945050505050565b612b0481612731565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b6060612b5f8383604051806060016040528060278152602001615917602791396130bf565b9392505050565b80515f90815b81811015612c22575f848281518110612b8757612b87614510565b016020015160f81c90505f612b9d6010836155ce565b90505f612bab6010846155e1565b90505f612bb9856002614143565b612bc49060106156d7565b612bce9083614143565b9050612bdb856002614143565b612be6906001615498565b612bf19060106156d7565b612bfb9084614143565b612c059082615498565b9050612c118188615498565b965050505050806001019050612b6c565b5050919050565b5f612c326134b6565b5f612c3f84826002612a67565b612c48906156e2565b90506001600160f01b03198116600360f81b14612c68575f925050915091565b5f612c7585600280612a67565b612c7e906156e2565b90506001600160f01b03198116600160f91b14612c9f575f93505050915091565b5f612cac86600480612a67565b612cb59061571c565b90506001600160e01b0319811615612cd2575f9450505050915091565b5f612ce087600c6010612a67565b612ce990615756565b90506001600160801b031981166f939a7233f79c4ca9940a0db3957f060760801b14612d1b575f955050505050915091565b6040805160e0810182526001600160f01b03198087168252851660208201526001600160e01b031984169181019190915260608101612d5d8960086002612a67565b612d66906156e2565b6001600160f01b0319168152602001612d8289600a6002612a67565b612d8b906156e2565b6001600160f01b03191681526001600160801b031983166020820152604001612db789601c6014612a67565b612dc090615790565b6001600160601b031916905260019890975095505050505050565b5f612de4613556565b604080518082019091525f815260606020820152612e0961286e866102406002612a67565b61ffff16808252612e1f90869061024290612a67565b602082015280515f90612e349061024261543b565b61ffff169050612e426135dd565b612e5161286e88846002612a67565b61ffff1680825260011180612e6d57506005815f015161ffff16115b15612e7d575f9450505050611b85565b612e88600283615498565b9150612e9961286e88846004612a67565b63ffffffff166020820152612eaf600483615498565b91505f612ed183836020015163ffffffff168a612a679092919063ffffffff16565b9050612edd8188613133565b604080840191909152612ef39089905f90612a67565b8552612f0188604080612a67565b60208601525f612f15896080610180612a67565b9050612f2081612f58565b604080880191909152612f38908a9061020090612a67565b6060870152505060808401929092525060a0820152600191509250929050565b612f606134f1565b612f6c825f6010612a67565b612f7590615756565b6001600160801b0319168152612f8e8260106004612a67565b612f979061571c565b6001600160e01b0319166020820152612fb3826014601c612a67565b612fbc906157ca565b63ffffffff19166040820152612fd58260306010612a67565b612fde90615756565b6001600160801b0319166060820152612ffa8260406020612a67565b613003906154fe565b60808201526130158260606020612a67565b61301e906154fe565b60a08201526130308260806020612a67565b613039906154fe565b60c082015261304b8260a06060612a67565b60e082015261306161286e836101006002612a67565b61ffff1661010082015261307c61286e836101026002612a67565b61ffff1661012082015261309482610104603c612a67565b610140808301919091526130ab9083906040612a67565b610160820152919050565b8082845e505050565b60605f5f856001600160a01b0316856040516130db91906150c2565b5f60405180830381855af49150503d805f8114613113576040519150601f19603f3d011682016040523d82523d5f602084013e613118565b606091505b5091509150613129868383876132d0565b9695505050505050565b61313b6135f7565b604051635b732b7d60e11b815282906060905f9081906001600160a01b0385169063b6e656fa90613173908a906003906004016157fe565b5f60405180830381865afa15801561318d573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526131b4919081019061581f565b91509150816131d657604051636237e47b60e11b815260040160405180910390fd5b6040805160038082526080820190925290816020015b6131f461346d565b8152602001906001900390816131ec5790505092505f5b600381101561325b5761323682828151811061322957613229614510565b6020026020010151613348565b82828151811061324857613248614510565b602090810291909101015260010161320b565b506040518060600160405280825f8151811061327957613279614510565b602002602001015181526020018260018151811061329957613299614510565b60200260200101518152602001826002815181106132b9576132b9614510565b602002602001015181525094505050505092915050565b6060831561333e5782515f03613337576001600160a01b0385163b6133375760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610790565b5081612678565b6126788383613443565b60608151801561343d5760038160021c026003821661337d5783820151613d3d18601e81901a1560ff90911615019003613386565b60038216015f19015b60405192508083526020830181810191507ffc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc80605b527804080c1014181c2024282c3034383c4044484c5054585c6064603b526ef8fcf800fcd0d4d8dce0e4e8ecf0f4601a525b600486019550855180601f1a5160061c81601e1a5183161760061c81601d1a5183161760061c81601c1a518316178352506003820191508282106133ed575050602081016040525f8152505f6060525b50919050565b8151156134535781518083602001fd5b8060405162461bcd60e51b815260040161079091906158e4565b6040518061010001604052805f81526020015f8152602001606081526020016060815260200160608152602001606081526020015f151581526020016134b161361e565b905290565b6040805160e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e082018190526101008201839052610120820192909252610140810182905261016081019190915290565b6040518060c0016040528060608152602001606081526020016135776134f1565b8152602001606081526020016135a360405180604001604052805f61ffff168152602001606081525090565b81526020016134b16135dd565b60405180606001604052806135c36134b6565b81526020016135d06134f1565b81526020016134b1613556565b604080516060810182525f80825260208201529081016134b15b60405180606001604052806003905b60608152602001906001900390816136065790505090565b604051806060016040528060608152602001606081526020016134b1604051806080016040528060608152602001606081526020015f8152602001606081525090565b5f60208284031215613671575f5ffd5b81356001600160401b03811115613686575f5ffd5b82016101208185031215612b5f575f5ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b8215158152604060208201525f6126786040830184613698565b5f602082840312156136f0575f5ffd5b81356001600160401b03811115613705575f5ffd5b820160e08185031215612b5f575f5ffd5b80356001600160a01b038116811461372c575f5ffd5b919050565b5f5f5f60608486031215613743575f5ffd5b61374c84613716565b925061375a60208501613716565b915061376860408501613716565b90509250925092565b5f5f5f60408486031215613783575f5ffd5b8335925060208401356001600160401b0381111561379f575f5ffd5b8401601f810186136137af575f5ffd5b80356001600160401b038111156137c4575f5ffd5b8660208260051b84010111156137d8575f5ffd5b939660209190910195509293505050565b5f602082840312156137f9575f5ffd5b5035919050565b5f60208284031215613810575f5ffd5b612b5f82613716565b8015158114610a46575f5ffd5b5f5f60408385031215613837575f5ffd5b82359150602083013561384981613819565b809150509250929050565b5f5f83601f840112613864575f5ffd5b5081356001600160401b0381111561387a575f5ffd5b602083019150836020828501011115611b85575f5ffd5b5f5f5f604084860312156138a3575f5ffd5b83356001600160401b038111156138b8575f5ffd5b6138c486828701613854565b90945092505060208401356001600160401b038111156138e2575f5ffd5b8401606081870312156138f3575f5ffd5b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b60405161018081016001600160401b0381118282101715613935576139356138fe565b60405290565b604051606081016001600160401b0381118282101715613935576139356138fe565b60405160c081016001600160401b0381118282101715613935576139356138fe565b60405160e081016001600160401b0381118282101715613935576139356138fe565b604051608081016001600160401b0381118282101715613935576139356138fe565b60405161010081016001600160401b0381118282101715613935576139356138fe565b604051601f8201601f191681016001600160401b0381118282101715613a0e57613a0e6138fe565b604052919050565b5f6001600160401b03821115613a2e57613a2e6138fe565b50601f01601f191660200190565b5f613a4e613a4984613a16565b6139e6565b9050828152838383011115613a61575f5ffd5b828260208301375f602084830101529392505050565b5f60208284031215613a87575f5ffd5b81356001600160401b03811115613a9c575f5ffd5b8201601f81018413613aac575f5ffd5b61267884823560208401613a3c565b604081525f613acd6040830185613698565b8281036020840152613adf8185613698565b95945050505050565b5f82601f830112613af7575f5ffd5b612b5f83833560208501613a3c565b5f5f60408385031215613b17575f5ffd5b613b2083613716565b915060208301356001600160401b03811115613b3a575f5ffd5b613b4685828601613ae8565b9150509250929050565b5f5f60208385031215613b61575f5ffd5b82356001600160401b03811115613b76575f5ffd5b613b8285828601613854565b90969095509350505050565b5f5f60408385031215613b9f575f5ffd5b8235915060208301356001600160401b03811115613b3a575f5ffd5b80356001600160f01b03198116811461372c575f5ffd5b6001600160e01b031981168114610a46575f5ffd5b803561372c81613bd2565b6001600160801b031981168114610a46575f5ffd5b803561372c81613bf2565b803563ffffffff198116811461372c575f5ffd5b61ffff81168114610a46575f5ffd5b803561372c81613c26565b5f6101808284031215613c51575f5ffd5b613c59613912565b9050613c6482613c07565b8152613c7260208301613be7565b6020820152613c8360408301613c12565b6040820152613c9460608301613c07565b60608201526080828101359082015260a0808301359082015260c0808301359082015260e08201356001600160401b03811115613ccf575f5ffd5b613cdb84828501613ae8565b60e083015250613cee6101008301613c35565b610100820152613d016101208301613c35565b6101208201526101408201356001600160401b03811115613d20575f5ffd5b613d2c84828501613ae8565b610140830152506101608201356001600160401b03811115613d4c575f5ffd5b613d5884828501613ae8565b6101608301525092915050565b5f60408284031215613d75575f5ffd5b604080519081016001600160401b0381118282101715613d9757613d976138fe565b6040529050808235613da881613c26565b815260208301356001600160401b03811115613dc2575f5ffd5b613dce85828601613ae8565b6020830152505092915050565b5f60608284031215613deb575f5ffd5b613df361393b565b90508135613e0081613c26565b8152602082013563ffffffff81168114613e18575f5ffd5b602082015260408201356001600160401b03811115613e35575f5ffd5b8201601f81018413613e45575f5ffd5b613e4d61393b565b806060830186811115613e5e575f5ffd5b835b81811015613e985780356001600160401b03811115613e7d575f5ffd5b613e8989828801613ae8565b85525060209384019301613e60565b5050604084015250909392505050565b5f60c08284031215613eb8575f5ffd5b613ec061395d565b905081356001600160401b03811115613ed7575f5ffd5b613ee384828501613ae8565b82525060208201356001600160401b03811115613efe575f5ffd5b613f0a84828501613ae8565b60208301525060408201356001600160401b03811115613f28575f5ffd5b613f3484828501613c40565b60408301525060608201356001600160401b03811115613f52575f5ffd5b613f5e84828501613ae8565b60608301525060808201356001600160401b03811115613f7c575f5ffd5b613f8884828501613d65565b60808301525060a08201356001600160401b03811115613fa6575f5ffd5b613fb284828501613ddb565b60a08301525092915050565b5f813603610120811215613fd0575f5ffd5b613fd861393b565b60e0821215613fe5575f5ffd5b613fed61397f565b9150613ff884613bbb565b825261400660208501613bbb565b6020830152604084013561401981613bd2565b604083015261402a60608501613bbb565b606083015261403b60808501613bbb565b608083015260a084013561404e81613bf2565b60a083015260c08401356001600160601b03198116811461406d575f5ffd5b60c083015290815260e0830135906001600160401b0382111561408e575f5ffd5b61409a36838601613c40565b602082015261010084013591506001600160401b038211156140ba575f5ffd5b6140c636838601613ea8565b60408201529392505050565b5f813561270581613c26565b5f813561270581613bf2565b5f5f8335601e198436030181126140ff575f5ffd5b8301803591506001600160401b03821115614118575f5ffd5b6020019150600681901b3603821315611b85575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176127055761270561412f565b60028110610a46575f5ffd5b634e487b7160e01b5f52602160045260245ffd5b813561418581613c26565b61ffff811661ffff19835416178255506001810160208301356141a78161415a565b600281106141b7576141b7614166565b60ff1982541660ff8216811783555050505050565b600160401b8311156141e0576141e06138fe565b805483825580841015614252576001600160ff1b03811681146142055761420561412f565b6001600160ff1b038416841461421d5761421d61412f565b815f5260205f208160011b81018560011b820191505b8082101561424f575f82555f6001830155600282019150614233565b50505b505f8181526020812083915b8581101561428657614270838361417a565b604092909201916002919091019060010161425e565b505050505050565b813561429981613bd2565b8060e01c63ffffffff198354161782555060208201356142b881613bd2565b815467ffffffff00000000191660c09190911c67ffffffff000000001617815561430d6142e7604084016140d2565b825469ffff0000000000000000191660409190911b69ffff000000000000000016178255565b61435861431c606084016140de565b8280546fffffffffffffffffffffffffffffffff60501b191660309290921c6fffffffffffffffffffffffffffffffff60501b16919091179055565b614382614367608084016140de565b600183018160801c6001600160801b03198254161781555050565b60a0820135600282015561439960c08301836140ea565b6108388183600386016141cc565b5f5f8335601e198436030181126143bc575f5ffd5b83016020810192503590506001600160401b038111156143da575f5ffd5b8060061b3603821315611b85575f5ffd5b8183526020830192505f815f5b8481101561444757813561440b81613c26565b61ffff168652602082013561441f8161415a565b6002811061442f5761442f614166565b602087015260409586019591909101906001016143f8565b5093949350505050565b602081525f823561446181613bd2565b6001600160e01b03191660208381019190915283013561448081613bd2565b63ffffffff60e01b811660408401525061449c60408401613c35565b61ffff81166060840152506144b360608401613c07565b6001600160801b031981166080840152506144d060808401613c07565b6001600160801b0319811660a08401525060a083013560c0838101919091526144fb908401846143a7565b60e080850152613adf610100850182846143eb565b634e487b7160e01b5f52603260045260245ffd5b5f5f8335601e19843603018112614539575f5ffd5b8301803591506001600160401b03821115614552575f5ffd5b602001915036819003821315611b85575f5ffd5b818382375f9101908152919050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b602081525f612678602083018486614575565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600181811c9082168061465c57607f821691505b60208210810361343d57634e487b7160e01b5f52602260045260245ffd5b5b81811015610d77575f815560010161467b565b601f82111561195b57805f5260205f20601f840160051c810160208510156146b35750805b610963601f850160051c83018261467a565b6001600160401b038311156146dc576146dc6138fe565b6146f0836146ea8354614648565b8361468e565b5f601f841160018114614721575f851561470a5750838201355b5f19600387901b1c1916600186901b178355610963565b5f83815260208120601f198716915b828110156147505786850135825560209485019460019092019101614730565b508682101561476c575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b5f5f8335601e19843603018112614793575f5ffd5b8301803591506001600160401b038211156147ac575f5ffd5b6020019150600581901b3603821315611b85575f5ffd5b5f8235605e198336030181126147d7575f5ffd5b9190910192915050565b80545f82558015610d7757815f5260205f2061195b601f830160051c82018261467a565b600160401b821115614819576148196138fe565b80548282558083101561195b57815f5260205f20601f840160051c8101601f85168015614855575f19820180545f198360200360031b1c168155505b50610963601f840160051c83018261467a565b60ff81168114610a46575f5ffd5b5f813561270581614868565b60088110610a46575f5ffd5b5f813561270581614882565b600882106148aa576148aa614166565b60ff1981541660ff831681178255505050565b81358155600181016148d2602084018461477e565b6001600160401b038111156148e9576148e96138fe565b6148f38184614805565b5f8381526020902092508060051c5f5b81811015614958575f5f5b602081101561494b5761493a61492387614876565b60ff908116600384901b90811b91901b1984161790565b60209690960195915060010161490e565b5085820155600101614903565b50601f198216808303818414614996575f5f5b828110156149905761497f61492388614876565b60209790970196915060010161496b565b50868401555b505050505050610d776149ab6040840161488e565b6002830161489a565b600160401b8311156149c8576149c86138fe565b805483825580841015614a3757806003026003810482146149eb576149eb61412f565b84600302600381048614614a0157614a0161412f565b5f8481526020902091820191015b81811015614a34575f8155614a26600182016147e1565b5f6002820155600301614a0f565b50505b505f8181526020812083915b8581101561428657614a5e614a5884876147c3565b836148bd565b6020929092019160039190910190600101614a43565b614a7e8283614524565b6001600160401b03811115614a9557614a956138fe565b614aa981614aa38554614648565b8561468e565b5f601f821160018114614ada575f8315614ac35750838201355b5f19600385901b1c1916600184901b178555614b31565b5f85815260208120601f198516915b82811015614b095786850135825560209485019460019092019101614ae9565b5084821015614b25575f1960f88660031b161c19848701351681555b505060018360011b0185555b50505050614b426020830183614524565b614b508183600186016146c5565b5050614b5f604083018361477e565b6108388183600286016149b4565b5f5f8335601e19843603018112614b82575f5ffd5b83016020810192503590506001600160401b03811115614ba0575f5ffd5b803603821315611b85575f5ffd5b5f5f8335601e19843603018112614bc3575f5ffd5b83016020810192503590506001600160401b03811115614be1575f5ffd5b8060051b3603821315611b85575f5ffd5b602081525f614c018384614b6d565b60606020850152614c16608085018284614575565b915050614c266020850185614b6d565b848303601f19016040860152614c3d838284614575565b92505050614c4e6040850185614bae565b848303601f19016060860152808352602080840190600583901b850101835f36829003605e19015b85821015614d2e57878403601f190185528235818112614c94575f5ffd5b87018035855260608501614cab6020830183614bae565b6060602089015291829052905f90608088015b81831015614ce9578335614cd181614868565b60ff1681526020938401936001939093019201614cbe565b60408501359450614cf985614882565b60088510614d0957614d09614166565b8460408a01528098505050505050602083019250602085019450600182019150614c76565b50919998505050505050505050565b604081525f614d4f6040830185613698565b905082151560208301529392505050565b805161372c81613819565b5f82601f830112614d7a575f5ffd5b8151602083015f614d8d613a4984613a16565b9050828152858383011115614da0575f5ffd5b8282602083015e5f92810160200192909252509392505050565b5f6001600160401b03821115614dd257614dd26138fe565b5060051b60200190565b5f60608284031215614dec575f5ffd5b614df461393b565b905081516001600160401b03811115614e0b575f5ffd5b614e1784828501614d6b565b82525060208201516001600160401b03811115614e32575f5ffd5b614e3e84828501614d6b565b60208301525060408201516001600160401b03811115614e5c575f5ffd5b820160808185031215614e6d575f5ffd5b614e756139a1565b81516001600160401b03811115614e8a575f5ffd5b614e9686828501614d6b565b82525060208201516001600160401b03811115614eb1575f5ffd5b614ebd86828501614d6b565b6020830152506040828101519082015260608201516001600160401b03811115614ee5575f5ffd5b80830192505084601f830112614ef9575f5ffd5b8151614f07613a4982614dba565b8082825260208201915060208360051b860101925087831115614f28575f5ffd5b6020850194505b82851015614f4a578451825260209485019490910190614f2f565b6060840152505060408301525092915050565b5f5f60408385031215614f6e575f5ffd5b8251614f7981613819565b60208401519092506001600160401b03811115614f94575f5ffd5b83016101008186031215614fa6575f5ffd5b614fae6139c3565b815181526020808301519082015260408201516001600160401b03811115614fd4575f5ffd5b614fe087828501614d6b565b60408301525060608201516001600160401b03811115614ffe575f5ffd5b61500a87828501614d6b565b60608301525060808201516001600160401b03811115615028575f5ffd5b61503487828501614d6b565b60808301525060a08201516001600160401b03811115615052575f5ffd5b61505e87828501614d6b565b60a08301525061507060c08301614d60565b60c082015260e08201516001600160401b0381111561508d575f5ffd5b61509987828501614ddc565b60e08301525080925050509250929050565b5f81518060208401855e5f93019283525090919050565b5f612b5f82846150ab565b80516001600160801b03191682525f60208201516150f760208501826001600160e01b0319169052565b506040820151615110604085018263ffffffff19169052565b50606082015161512c60608501826001600160801b0319169052565b506080820151608084015260a082015160a084015260c082015160c084015260e082015161018060e0850152615166610180850182613698565b905061010083015161517f61010086018261ffff169052565b5061012083015161519761012086018261ffff169052565b506101408301518482036101408601526151b18282613698565b915050610160830151848203610160860152613adf8282613698565b5f6060830161ffff835116845263ffffffff60208401511660208501526040830151606060408601528182905060c0860192505f5b600381101561523457605f1987850301825261521f848451613698565b93506020928301929190910190600101615202565b509195945050505050565b5f815160c0845261525360c0850182613698565b90506020830151848203602086015261526c8282613698565b9150506040830151848203604086015261528682826150cd565b915050606083015184820360608601526152a08282613698565b9150506080830151848203608086015261ffff815116825260208101519050604060208301526152d36040830182613698565b91505060a083015184820360a0860152613adf82826151cd565b602081525f825161ffff60f01b815116602084015261ffff60f01b602082015116604084015263ffffffff60e01b604082015116606084015261ffff60f01b606082015116608084015261ffff60f01b60808201511660a084015260a081015161536360c08501826001600160801b0319169052565b5060c001516001600160601b03191660e083015260208301516101206101008401526153936101408401826150cd565b90506040840151601f1984830301610120850152613adf828261523f565b5f602082840312156153c1575f5ffd5b5051919050565b8281525f600883106153dc576153dc614166565b5060f89190911b6020820152602101919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b61ffff81811683821601908111156127055761270561412f565b63ffffffff81811683821601908111156127055761270561412f565b5f61267861547f83866150ab565b846150ab565b818103818111156127055761270561412f565b808201808211156127055761270561412f565b606081525f6154bd6060830186613698565b82810360208401526154cf8186613698565b905082810360408401526131298185613698565b5f602082840312156154f3575f5ffd5b8151612b5f81613819565b8051602080830151919081101561343d575f1960209190910360031b1b16919050565b6001600160801b03198d811682526001600160e01b03198d16601083015263ffffffff198c1660148301528a1660308201526040810189905260608101889052608081018790525f61557660a08301886150ab565b6001600160f01b031960f088811b8216835287901b1660028201526155a76155a160048301876150ab565b856150ab565b9f9e505050505050505050505050505050565b634e487b7160e01b5f52601260045260245ffd5b5f826155dc576155dc6155ba565b500490565b5f826155ef576155ef6155ba565b500690565b6001815b600184111561562f578085048111156156135761561361412f565b600184161561562157908102905b60019390931c9280026155f8565b935093915050565b5f8261564557506001612705565b8161565157505f612705565b816001811461566757600281146156715761568d565b6001915050612705565b60ff8411156156825761568261412f565b50506001821b612705565b5060208310610133831016604e8410600b84101617156156b0575081810a612705565b6156bc5f1984846155f4565b805f19048211156156cf576156cf61412f565b029392505050565b5f612b5f8383615637565b805160208201516001600160f01b0319811691906002821015612c22576001600160f01b031960029290920360031b82901b161692915050565b805160208201516001600160e01b0319811691906004821015612c22576001600160e01b031960049290920360031b82901b161692915050565b805160208201516001600160801b0319811691906010821015612c22576001600160801b031960109290920360031b82901b161692915050565b805160208201516001600160601b0319811691906014821015612c22576001600160601b031960149290920360031b82901b161692915050565b8051602082015163ffffffff1981169190601c821015612c225763ffffffff19601c9290920360031b82901b161692915050565b604081525f6158106040830185613698565b90508260208301529392505050565b5f5f60408385031215615830575f5ffd5b825161583b81613819565b60208401519092506001600160401b03811115615856575f5ffd5b8301601f81018513615866575f5ffd5b8051615874613a4982614dba565b8082825260208201915060208360051b850101925087831115615895575f5ffd5b602084015b838110156158d55780516001600160401b038111156158b7575f5ffd5b6158c68a602083890101614d6b565b8452506020928301920161589a565b50809450505050509250929050565b602081525f612b5f602083018461369856fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122020c9aee297253a1c57d6d5d86853a955f3d1d76f0c7a7f66c872a18af583810f64736f6c634300081e0033