Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 6 from a total of 6 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Originate | 19270921 | 286 days ago | IN | 0 ETH | 0.00683527 | ||||
Originate | 19234289 | 291 days ago | IN | 0 ETH | 0.01216283 | ||||
Originate | 19233804 | 291 days ago | IN | 0 ETH | 0.00713006 | ||||
Invalidate Cavea... | 19220017 | 293 days ago | IN | 0 ETH | 0.00175786 | ||||
Refinance | 19178277 | 299 days ago | IN | 0 ETH | 0.00993474 | ||||
Originate | 19088441 | 312 days ago | IN | 0 ETH | 0.00334972 |
Latest 2 internal transactions
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
19087726 | 312 days ago | Contract Creation | 0 ETH | |||
19087726 | 312 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Starport
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 // // ↑↑↑↑ ↑↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑ ↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑ ↑↑↑↑ ↑ ↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ Starport: Lending Kernel // ↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑↑↑↑↑ Designed with love by Astaria Labs, Inc // ↑↑↑↑ ↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ pragma solidity ^0.8.17; import {CaveatEnforcer} from "./enforcers/CaveatEnforcer.sol"; import {Custodian} from "./Custodian.sol"; import {PausableNonReentrant} from "./lib/PausableNonReentrant.sol"; import {Pricing} from "./pricing/Pricing.sol"; import {Status} from "./status/Status.sol"; import {Settlement} from "./settlement/Settlement.sol"; import {StarportLib, AdditionalTransfer} from "./lib/StarportLib.sol"; import {SpentItem, ItemType} from "seaport-types/src/lib/ConsiderationStructs.sol"; import {ERC20} from "solady/src/tokens/ERC20.sol"; import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol"; import {SafeTransferLib} from "solady/src/utils/SafeTransferLib.sol"; import {SignatureCheckerLib} from "solady/src/utils/SignatureCheckerLib.sol"; interface Stargate { function getOwner(address) external returns (address); } contract Starport is PausableNonReentrant { using FixedPointMathLib for uint256; using {StarportLib.getId} for Starport.Loan; using {StarportLib.validateSalt} for mapping(address => mapping(bytes32 => bool)); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ error CaveatDeadlineExpired(); error InvalidFeeRakeBps(); error InvalidCaveat(); error InvalidCaveatLength(); error InvalidCaveatSigner(); error InvalidCustodian(); error InvalidLoan(); error InvalidLoanState(); error InvalidPostRepayment(); error LoanExists(); error MalformedRefinance(); error NotLoanCustodian(); error UnauthorizedAdditionalTransferIncluded(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ event ApprovalSet(address indexed owner, address indexed spender, uint8 approvalType); event CaveatFilled(address owner, bytes32 hash, bytes32 salt); event CaveatNonceIncremented(address owner, uint256 newNonce); event CaveatSaltInvalidated(address owner, bytes32 salt); event Close(uint256 loanId); event FeeDataUpdated(address feeTo, uint88 defaultFeeRakeBps); event FeeOverrideUpdated(address token, uint88 overrideBps, bool enabled); event Open(uint256 loanId, Starport.Loan loan); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS AND IMMUTABLES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ uint88 public constant MAX_FEE_RAKE_BPS = 500; // 5% uint88 public constant BPS_DENOMINATOR = 10_000; // 100% uint256 public constant LOAN_CLOSED_FLAG = 0x0; uint256 public constant LOAN_OPEN_FLAG = 0x1; bytes32 private constant _INVALID_LOAN = 0x045f33d100000000000000000000000000000000000000000000000000000000; bytes32 private constant _LOAN_EXISTS = 0x14ec57fc00000000000000000000000000000000000000000000000000000000; Stargate public immutable SG; uint256 public immutable chainId; bytes32 public immutable DEFAULT_CUSTODIAN_CODE_HASH; bytes32 public immutable CACHED_DOMAIN_SEPARATOR; // Define the EIP712 domain and typeHash constants for generating signatures bytes32 public constant EIP_DOMAIN = keccak256("EIP712Domain(" "string name," "string version," "uint256 chainId," "address verifyingContract" ")"); bytes32 public constant VERSION = keccak256(bytes("0")); bytes32 public constant NAME = keccak256(bytes("Starport")); bytes32 public constant INTENT_ORIGINATION_TYPEHASH = keccak256( "Origination(" "address account," "uint256 accountNonce," "bool singleUse," "bytes32 salt," "uint256 deadline," "Caveat[] caveats" ")" "Caveat(" "address enforcer," "bytes data" ")" ); bytes32 public constant CAVEAT_TYPEHASH = keccak256("Caveat(" "address enforcer," "bytes data" ")"); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ struct Terms { address status; // the address of the status module bytes statusData; // bytes encoded hook data address pricing; // the address of the pricing module bytes pricingData; // bytes encoded pricing data address settlement; // the address of the handler module bytes settlementData; // bytes encoded handler data } struct Loan { uint256 start; // start of the loan address custodian; // where the collateral is being held address borrower; // the borrower address issuer; // the capital issuer/lender address originator; // who originated the loan SpentItem[] collateral; // array of collateral SpentItem[] debt; // array of debt Terms terms; // the actionable terms of the loan } struct FeeOverride { bool enabled; uint88 bpsOverride; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ENUMS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ enum ApprovalType { NOTHING, BORROWER, LENDER } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ address public feeTo; uint256 public defaultFeeRakeBps; mapping(address => FeeOverride) public feeOverrides; mapping(address => mapping(address => ApprovalType)) public approvals; mapping(address => mapping(bytes32 => bool)) public invalidSalts; mapping(address => uint256) public caveatNonces; mapping(uint256 => uint256) public loanState; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTRUCTOR */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ constructor(address seaport_, Stargate stargate_, address owner_) { SG = stargate_; chainId = block.chainid; CACHED_DOMAIN_SEPARATOR = keccak256(abi.encode(EIP_DOMAIN, NAME, VERSION, block.chainid, address(this))); address custodian = address(new Custodian(this, seaport_)); bytes32 defaultCustodianCodeHash; assembly ("memory-safe") { defaultCustodianCodeHash := extcodehash(custodian) } DEFAULT_CUSTODIAN_CODE_HASH = defaultCustodianCodeHash; _initializeOwner(owner_); } function domainSeparator() public view returns (bytes32) { //return the cached domain separator if the chainId is the same if (chainId == block.chainid) { return CACHED_DOMAIN_SEPARATOR; } return keccak256(abi.encode(EIP_DOMAIN, NAME, VERSION, block.chainid, address(this))); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev Sets approval to originate loans without having to check caveats * @param who The address of who is being approved * @param approvalType The type of approval (Borrower, Lender) (cant be both) */ function setOriginateApproval(address who, ApprovalType approvalType) external { approvals[msg.sender][who] = approvalType; emit ApprovalSet(msg.sender, who, uint8(approvalType)); } /** * @dev The loan origination method, new loan data is passed in and validated before being issued * @param additionalTransfers Additional transfers to be made after the loan is issued * @param borrowerCaveat The borrower caveat to be validated * @param lenderCaveat The lender caveat to be validated * @param loan The loan to be issued */ function originate( AdditionalTransfer[] calldata additionalTransfers, CaveatEnforcer.SignedCaveats calldata borrowerCaveat, CaveatEnforcer.SignedCaveats calldata lenderCaveat, Starport.Loan memory loan ) external payable pausableNonReentrant { // Cache the addresses address borrower = loan.borrower; address issuer = loan.issuer; address feeRecipient = feeTo; if (msg.sender != borrower && approvals[borrower][msg.sender] != ApprovalType.BORROWER) { _validateAndEnforceCaveats(borrowerCaveat, borrower, additionalTransfers, loan); } if (msg.sender != issuer && approvals[issuer][msg.sender] != ApprovalType.LENDER) { _validateAndEnforceCaveats(lenderCaveat, issuer, additionalTransfers, loan); } StarportLib.transferSpentItems(loan.collateral, borrower, loan.custodian, true); if (feeRecipient == address(0)) { StarportLib.transferSpentItems(loan.debt, issuer, borrower, false); } else { (SpentItem[] memory feeItems, SpentItem[] memory sentToBorrower) = _feeRake(loan.debt); if (feeItems.length > 0) { StarportLib.transferSpentItems(feeItems, issuer, feeRecipient, false); } StarportLib.transferSpentItems(sentToBorrower, issuer, borrower, false); } if (additionalTransfers.length > 0) { _validateAdditionalTransfersOriginate(borrower, issuer, msg.sender, additionalTransfers); StarportLib.transferAdditionalTransfersCalldata(additionalTransfers); } // Sets originator and start time _issueLoan(loan); _callCustody(loan); } /** * @dev Refinances an existing loan with new pricing data, its the only thing that can be changed * @param lender The new lender * @param lenderCaveat The lender caveat to be validated * @param loan The loan to be issued * @param pricingData The new pricing data */ function refinance( address lender, CaveatEnforcer.SignedCaveats calldata lenderCaveat, Starport.Loan memory loan, bytes calldata pricingData, bytes calldata extraData ) external pausableNonReentrant { if (loan.start == block.timestamp) { revert InvalidLoan(); } if (!Status(loan.terms.status).isActive(loan, extraData)) { revert InvalidLoanState(); } ( SpentItem[] memory considerationPayment, SpentItem[] memory carryPayment, AdditionalTransfer[] memory additionalTransfers ) = Pricing(loan.terms.pricing).getRefinanceConsideration(loan, pricingData, msg.sender); _settle(loan); _postRepaymentExecute(loan, msg.sender); StarportLib.transferSpentItems(considerationPayment, lender, loan.issuer, false); if (carryPayment.length > 0) { StarportLib.transferSpentItems(carryPayment, lender, loan.originator, false); } loan.debt = applyRefinanceConsiderationToLoan(considerationPayment, carryPayment); loan.terms.pricingData = pricingData; loan.issuer = lender; loan.originator = address(0); loan.start = 0; if (msg.sender != lender && approvals[lender][msg.sender] != ApprovalType.LENDER) { _validateAndEnforceCaveats(lenderCaveat, lender, additionalTransfers, loan); } if (additionalTransfers.length > 0) { _validateAdditionalTransfersRefinance(lender, msg.sender, additionalTransfers); StarportLib.transferAdditionalTransfers(additionalTransfers); } // Sets originator and start time _issueLoan(loan); } /** * @dev Helper to settle a loan * guarded to ensure only the loan.custodian can call it * @param loan The entire loan struct */ function settle(Loan memory loan) external { if (msg.sender != loan.custodian) { revert NotLoanCustodian(); } _settle(loan); } /** * @dev Increments caveat nonce for sender and emits event */ function incrementCaveatNonce() external { unchecked { uint256 newNonce = caveatNonces[msg.sender] + 1 + uint256(blockhash(block.number - 1) >> 0x80); caveatNonces[msg.sender] = newNonce; emit CaveatNonceIncremented(msg.sender, newNonce); } } /** * @dev Invalidates a caveat salt * @param salt The salt to invalidate */ function invalidateCaveatSalt(bytes32 salt) external { invalidSalts.validateSalt(msg.sender, salt); emit CaveatSaltInvalidated(msg.sender, salt); } /** * @dev Sets the default fee data, only owner can call * @param feeTo_ The feeToAddress * @param defaultFeeRakeBps_ The default fee rake in basis points */ function setFeeData(address feeTo_, uint88 defaultFeeRakeBps_) external onlyOwner { if (defaultFeeRakeBps_ > MAX_FEE_RAKE_BPS) { revert InvalidFeeRakeBps(); } feeTo = feeTo_; defaultFeeRakeBps = defaultFeeRakeBps_; emit FeeDataUpdated(feeTo_, defaultFeeRakeBps_); } /** * @dev Sets fee overrides for specific tokens, only owner can call * @param token The token to override * @param bpsOverride The new basis points to override to (1 = 0.01%) * @param enabled Whether or not the override is enabled */ function setFeeOverride(address token, uint88 bpsOverride, bool enabled) external onlyOwner { if (bpsOverride > MAX_FEE_RAKE_BPS) { revert InvalidFeeRakeBps(); } feeOverrides[token] = FeeOverride({enabled: enabled, bpsOverride: bpsOverride}); emit FeeOverrideUpdated(token, bpsOverride, enabled); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev Refinances an existing loan with new pricing data, its the only thing that can be changed * @param considerationPayment the payment consideration * @param carryPayment The loan to be issued */ function applyRefinanceConsiderationToLoan(SpentItem[] memory considerationPayment, SpentItem[] memory carryPayment) public pure returns (SpentItem[] memory newDebt) { if ( considerationPayment.length == 0 || (carryPayment.length != 0 && considerationPayment.length != carryPayment.length) ) { revert MalformedRefinance(); } if (carryPayment.length > 0) { newDebt = new SpentItem[](considerationPayment.length); uint256 i = 0; for (; i < considerationPayment.length;) { newDebt[i] = considerationPayment[i]; newDebt[i].amount += carryPayment[i].amount; if (newDebt[i].itemType == ItemType.ERC721 && newDebt[i].amount > 1) { revert MalformedRefinance(); } unchecked { ++i; } } return newDebt; } else { uint256 i = 0; for (; i < considerationPayment.length;) { if (considerationPayment[i].itemType == ItemType.ERC721 && considerationPayment[i].amount > 1) { revert MalformedRefinance(); } unchecked { ++i; } } return considerationPayment; } } /** * @dev Helper to hash a caveat with a salt and nonce * @param account The account that is originating the loan * @param singleUse Whether to invalidate the salt after validation * @param salt The salt to use * @param deadline The deadline of the caveat * @param caveats The caveats to hash * @return bytes32 The hash of the caveat */ function hashCaveatWithSaltAndNonce( address account, bool singleUse, bytes32 salt, uint256 deadline, CaveatEnforcer.Caveat[] calldata caveats ) public view virtual returns (bytes32) { bytes32[] memory caveatHashes = new bytes32[](caveats.length); uint256 i = 0; for (; i < caveats.length;) { caveatHashes[i] = _hashCaveat(caveats[i]); unchecked { ++i; } } return keccak256( abi.encodePacked( bytes1(0x19), bytes1(0x01), domainSeparator(), keccak256( abi.encode( INTENT_ORIGINATION_TYPEHASH, account, caveatNonces[account], singleUse, salt, deadline, keccak256(abi.encodePacked(caveatHashes)) ) ) ) ); } /** * @dev Internal view function to derive the EIP-712 hash for a caveat * * @param caveat The caveat to hash. * * @return The hash. */ function _hashCaveat(CaveatEnforcer.Caveat memory caveat) internal pure returns (bytes32) { return keccak256(abi.encode(CAVEAT_TYPEHASH, caveat.enforcer, keccak256(caveat.data))); } /** * @dev Helper to check if a loan is open * @param loanId The id of the loan * @return bool True if the loan is open */ function open(uint256 loanId) public view returns (bool) { return loanState[loanId] == LOAN_OPEN_FLAG; } /** * @dev Helper to check if a loan is closed * @param loanId The id of the loan * @return bool True if the loan is closed */ function closed(uint256 loanId) public view returns (bool) { return loanState[loanId] == LOAN_CLOSED_FLAG; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev Calls postRepayment hook on loan Settlement module * @param loan The the loan that is being refrenced * @param fulfiller The address executing the settle */ function _postRepaymentExecute(Starport.Loan memory loan, address fulfiller) internal virtual { if (Settlement(loan.terms.settlement).postRepayment(loan, fulfiller) != Settlement.postRepayment.selector) { revert InvalidPostRepayment(); } } /** * @dev Internal method to call the custody selector of the custodian if it does not share * the same codehash as the default custodian * @param loan The loan being placed into custody */ function _callCustody(Starport.Loan memory loan) internal { address custodian = loan.custodian; // Comparing the retrieved code hash with a known hash bytes32 codeHash; assembly ("memory-safe") { codeHash := extcodehash(custodian) } if (codeHash != DEFAULT_CUSTODIAN_CODE_HASH && Custodian(custodian).custody(loan) != Custodian.custody.selector) { revert InvalidCustodian(); } } /** * @dev Internal method to validate additional transfers, only transfer from lender and fullfiller are valid * @param lender The lender of the loan * @param fulfiller The fulfiller of the loan * @param additionalTransfers The additional transfers to validate */ function _validateAdditionalTransfersRefinance( address lender, address fulfiller, AdditionalTransfer[] memory additionalTransfers ) internal pure { uint256 i = 0; for (; i < additionalTransfers.length;) { address from = additionalTransfers[i].from; if (from != lender && from != fulfiller) { revert UnauthorizedAdditionalTransferIncluded(); } unchecked { ++i; } } } /** * @dev Internal method to validate additional transfers, only transfers from borrower, lender, and fullfiller are valid * @param borrower The borrower of the loan * @param lender The lender of the loan * @param fulfiller The fulfiller of the loan * @param additionalTransfers The additional transfers to validate */ function _validateAdditionalTransfersOriginate( address borrower, address lender, address fulfiller, AdditionalTransfer[] calldata additionalTransfers ) internal pure { uint256 i = 0; for (; i < additionalTransfers.length;) { address from = additionalTransfers[i].from; if (from != borrower && from != lender && from != fulfiller) { revert UnauthorizedAdditionalTransferIncluded(); } unchecked { ++i; } } } /** * @dev Internal method to validate and enforce caveats * @param signedCaveats The signed caveats to validate * @param validator The validator of the caveats * @param additionalTransfers The additional transfers to validate * @param loan The loan to validate */ function _validateAndEnforceCaveats( CaveatEnforcer.SignedCaveats calldata signedCaveats, address validator, AdditionalTransfer[] memory additionalTransfers, Starport.Loan memory loan ) internal { bytes32 hash = hashCaveatWithSaltAndNonce( validator, signedCaveats.singleUse, signedCaveats.salt, signedCaveats.deadline, signedCaveats.caveats ); if (signedCaveats.singleUse) { invalidSalts.validateSalt(validator, signedCaveats.salt); //Validates and invalidates salt emit CaveatFilled(validator, hash, signedCaveats.salt); } else if (invalidSalts[validator][signedCaveats.salt]) { revert StarportLib.InvalidSalt(); } if (block.timestamp > signedCaveats.deadline) { revert CaveatDeadlineExpired(); } if (!SignatureCheckerLib.isValidSignatureNowCalldata(validator, hash, signedCaveats.signature)) { revert InvalidCaveatSigner(); } if (signedCaveats.caveats.length == 0) { revert InvalidCaveatLength(); } for (uint256 i = 0; i < signedCaveats.caveats.length;) { if ( CaveatEnforcer(signedCaveats.caveats[i].enforcer).validate( additionalTransfers, loan, signedCaveats.caveats[i].data ) != CaveatEnforcer.validate.selector ) { revert InvalidCaveat(); } unchecked { ++i; } } } /** * @dev Internal helper to settle a loan * @param loan The entire loan struct */ function _settle(Loan memory loan) internal { uint256 loanId = loan.getId(); assembly { mstore(0x0, loanId) mstore(0x20, loanState.slot) // loanState[loanId] let loc := keccak256(0x0, 0x40) // if (inactive(loanId)) { if iszero(sload(loc)) { // revert InvalidLoan() mstore(0x0, _INVALID_LOAN) revert(0x0, 0x04) } sstore(loc, LOAN_CLOSED_FLAG) } emit Close(loanId); } /** * @dev Sets fee overrides for specific tokens, only owner can call * @param debt The debt to rake * @return feeItems SpentItem[] of fees */ function _feeRake(SpentItem[] memory debt) internal view returns (SpentItem[] memory feeItems, SpentItem[] memory paymentToBorrower) { feeItems = new SpentItem[](debt.length); paymentToBorrower = new SpentItem[](debt.length); uint256 _defaultFeeRakeBps = defaultFeeRakeBps; uint256 totalFeeItems; for (uint256 i = 0; i < debt.length;) { uint256 amount; SpentItem memory debtItem = debt[i]; if (debtItem.itemType == ItemType.ERC20) { FeeOverride memory feeOverride = feeOverrides[debtItem.token]; SpentItem memory feeItem = feeItems[totalFeeItems]; feeItem.identifier = 0; uint256 bps = feeOverride.enabled ? feeOverride.bpsOverride : _defaultFeeRakeBps; amount = debtItem.amount.mulDivUp(bps, BPS_DENOMINATOR); if (amount > 0) { feeItem.amount = amount; feeItem.token = debtItem.token; feeItem.itemType = debtItem.itemType; unchecked { ++totalFeeItems; } } } paymentToBorrower[i] = SpentItem({ token: debtItem.token, itemType: debtItem.itemType, identifier: debtItem.identifier, amount: debtItem.amount - amount }); unchecked { ++i; } } assembly ("memory-safe") { mstore(feeItems, totalFeeItems) } } function acquireTokens(SpentItem[] memory items) external { StarportLib.transferSpentItems(items, SG.getOwner(msg.sender), msg.sender, false); } /** * @dev Changes loanId status to open for the specified loan * @param loan The loan to issue */ function _issueLoan(Loan memory loan) internal { loan.start = block.timestamp; loan.originator = loan.originator != address(0) ? loan.originator : msg.sender; uint256 loanId = loan.getId(); assembly { mstore(0x0, loanId) mstore(0x20, loanState.slot) // loanState[loanId] let loc := keccak256(0x0, 0x40) // if (active(loanId)) if iszero(iszero(sload(loc))) { // revert LoanExists() mstore(0x0, _LOAN_EXISTS) revert(0x0, 0x04) } sstore(loc, LOAN_OPEN_FLAG) } emit Open(loanId, loan); } }
// SPDX-License-Identifier: BUSL-1.1 // // ↑↑↑↑ ↑↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑ ↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑ ↑↑↑↑ ↑ ↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ Starport: Lending Kernel // ↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑↑↑↑↑ Designed with love by Astaria Labs, Inc // ↑↑↑↑ ↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ pragma solidity ^0.8.17; import {Starport} from "../Starport.sol"; import {AdditionalTransfer} from "../lib/StarportLib.sol"; abstract contract CaveatEnforcer { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ struct Caveat { address enforcer; bytes data; } struct SignedCaveats { bool singleUse; uint256 deadline; bytes32 salt; Caveat[] caveats; bytes signature; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* FUNCTION OVERRIDES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev Enforces that the loan terms are identical except for the issuer * @param solution The additional transfers to be made * @param loan The loan terms * @param caveatData The borrowers encoded details */ function validate(AdditionalTransfer[] calldata solution, Starport.Loan calldata loan, bytes calldata caveatData) public view virtual returns (bytes4); }
// SPDX-License-Identifier: BUSL-1.1 // // ↑↑↑↑ ↑↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑ ↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑ ↑↑↑↑ ↑ ↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ Starport: Lending Kernel // ↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑↑↑↑↑ Designed with love by Astaria Labs, Inc // ↑↑↑↑ ↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ pragma solidity ^0.8.17; import {Starport} from "./Starport.sol"; import {Pricing} from "./pricing/Pricing.sol"; import {Settlement} from "./settlement/Settlement.sol"; import {Status} from "./status/Status.sol"; import {StarportLib, Actions} from "./lib/StarportLib.sol"; import {ContractOffererInterface} from "seaport-types/src/interfaces/ContractOffererInterface.sol"; import {ItemType, Schema, SpentItem, ReceivedItem} from "seaport-types/src/lib/ConsiderationStructs.sol"; import {ERC20} from "solady/src/tokens/ERC20.sol"; import {ERC721} from "solady/src/tokens/ERC721.sol"; import {ERC1155} from "solady/src/tokens/ERC1155.sol"; import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol"; import {SafeTransferLib} from "solady/src/utils/SafeTransferLib.sol"; import {LibString} from "solady/src/utils/LibString.sol"; contract Custodian is ERC721, ContractOffererInterface { using {StarportLib.getId} for Starport.Loan; using {LibString.concat} for string; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ error CustodianCannotBeAuthorized(); error ImplementInChild(); error InvalidAction(); error InvalidFulfiller(); error InvalidLoan(); error InvalidPostRepayment(); error InvalidPostSettlement(); error InvalidRepayer(); error NotAuthorized(); error NotEnteredViaSeaport(); error NotSeaport(); error NotStarport(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ event SeaportCompatibleContractDeployed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS AND IMMUTABLES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ Starport public immutable SP; address public immutable seaport; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ struct Command { Actions action; Starport.Loan loan; bytes extraData; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTRUCTOR */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ constructor(Starport SP_, address seaport_) { seaport = seaport_; SP = SP_; emit SeaportCompatibleContractDeployed(); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* FUNCTION OVERRIDES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev The name of the ERC721 contract * @return string The name of the contract */ function name() public pure override returns (string memory) { return "Starport Custodian"; } /** * @dev The symbol of the ERC721 contract * @return string The symbol of the contract */ function symbol() public pure override returns (string memory) { return "SC"; } /** * @dev ERC-721 tokenURI override * @param loanId The id of the custody token/loan * @return string URI of the custody token/loan */ function tokenURI(uint256 loanId) public view override returns (string memory) { if (!_exists(loanId)) { revert InvalidLoan(); } return string("https://astaria.xyz/metadata/loan/").concat(LibString.toString(loanId)); } /** * @dev Helper to determine if an interface is supported by this contract * @param interfaceId The interface to check * @return bool Returns true if the interface is supported */ function supportsInterface(bytes4 interfaceId) public view override (ERC721, ContractOffererInterface) returns (bool) { return interfaceId == type(ERC721).interfaceId || interfaceId == type(ContractOffererInterface).interfaceId || super.supportsInterface(interfaceId); } /** * @dev onERC1155Received handler, if we are able to increment the counter * in seaport that means we have not entered into seaport we dont add for * ERC-721 as they are able to ignore the on handler call as apart of the spec * revert with NotEnteredViaSeaport() */ function onERC1155Received(address, address, uint256, uint256, bytes calldata) public virtual returns (bytes4) { return this.onERC1155Received.selector; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev Mints a custody token for a loan. * @param loan The loan to mint a custody token for */ function mint(Starport.Loan calldata loan) external { _validateAndMint(loan); } /** * @dev Mints a custody token for a loan. * @param loan The loan to mint a custody token for * @param approvedTo The address with pre approvals set */ function mintWithApprovalSet(Starport.Loan calldata loan, address approvedTo) external { if (msg.sender != loan.borrower) { revert NotAuthorized(); } _approve(loan.borrower, approvedTo, _validateAndMint(loan)); } /** * @dev internal helper that validates and mints a custody token for a loan. * @param loan The loan to mint a custody token for */ function _validateAndMint(Starport.Loan calldata loan) internal returns (uint256 loanId) { loanId = loan.getId(); if (loan.custodian != address(this) || SP.closed(loanId)) { revert InvalidLoan(); } _safeMint(loan.borrower, loanId); } /** * @dev Generates the order for this contract offerer * @return ratifyOrderMagicValue The magic value returned by the ratify */ function ratifyOrder(SpentItem[] calldata, ReceivedItem[] calldata, bytes calldata, bytes32[] calldata, uint256) external view onlySeaport returns (bytes4 ratifyOrderMagicValue) { ratifyOrderMagicValue = ContractOffererInterface.ratifyOrder.selector; } /** * @dev Generates the order for this contract offerer * @param fulfiller The address of the contract fulfiller * @param context The context of the order * @return offer The items spent by the order * @return consideration The items received by the order */ function generateOrder( address fulfiller, SpentItem[] calldata, SpentItem[] calldata, bytes calldata context // encoded based on the schemaID ) external onlySeaport returns (SpentItem[] memory offer, ReceivedItem[] memory consideration) { (Command memory close) = abi.decode(context, (Command)); Starport.Loan memory loan = close.loan; if (loan.start == block.timestamp) { revert InvalidLoan(); } bool loanActive = Status(loan.terms.status).isActive(loan, close.extraData); if (close.action == Actions.Repayment && loanActive) { if (fulfiller != getBorrower(loan) && fulfiller != _getApproved(loan.getId())) { revert InvalidRepayer(); } offer = loan.collateral; _setOfferApprovalsWithSeaport(loan); (SpentItem[] memory payment, SpentItem[] memory carry) = Pricing(loan.terms.pricing).getPaymentConsideration(loan); consideration = StarportLib.mergeSpentItemsToReceivedItems({ payment: payment, paymentRecipient: loan.issuer, carry: carry, carryRecipient: loan.originator }); _settleLoan(loan); _postRepaymentExecute(loan, fulfiller); } else if (close.action == Actions.Settlement && !loanActive) { address authorized; _beforeGetSettlementConsideration(loan); (consideration, authorized) = Settlement(loan.terms.settlement).getSettlementConsideration(loan); if (authorized == address(this)) { revert CustodianCannotBeAuthorized(); } consideration = StarportLib.removeZeroAmountItems(consideration); _afterGetSettlementConsideration(loan); if (authorized == address(0) || fulfiller == authorized) { offer = loan.collateral; _setOfferApprovalsWithSeaport(loan); } else if (authorized == loan.terms.settlement || authorized == loan.issuer) { _moveCollateralToAuthorized(loan.collateral, authorized); } else { revert InvalidFulfiller(); } _settleLoan(loan); _postSettlementExecute(loan, fulfiller); } else { revert InvalidAction(); } } /** * @dev If any additional state updates are needed when taking custody of a loan * @param loan The loan that was just placed into custody * @return selector The function selector of the custody method */ function custody(Starport.Loan memory loan) external virtual onlyStarport returns (bytes4 selector) { revert ImplementInChild(); } /** * @dev Returns metadata on how to interact with the offerer contract * @return string The name of the contract * @return schemas An array of supported schemas */ function getSeaportMetadata() external pure returns (string memory, Schema[] memory schemas) { // Adhere to SIP data, how to encode the context and what it is // TODO: add in the context for the loan // you need to parse SP Open events for the loan and ABI encode it schemas = new Schema[](1); schemas[0] = Schema(8, ""); return ("Loans", schemas); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev Fetches the borrower of the loan, first checks to see if we've minted the token for the loan * @param loan Loan to get the borrower of * @return address The address of the loan borrower(returns the ownerOf the token if any) defaults to loan.borrower */ function getBorrower(Starport.Loan memory loan) public view returns (address) { uint256 loanId = loan.getId(); return _exists(loanId) ? ownerOf(loanId) : loan.borrower; } /** * @dev Previews the order for this contract offerer * @param caller The address of the seaport contract * @param fulfiller The address of the contract fulfiller * @param context The context of the order * @return offer The items spent by the order * @return consideration The items received by the order */ function previewOrder( address caller, address fulfiller, SpentItem[] calldata, SpentItem[] calldata, bytes calldata context // Encoded based on the schemaID ) public view returns (SpentItem[] memory offer, ReceivedItem[] memory consideration) { if (caller != address(seaport)) revert NotSeaport(); (Command memory close) = abi.decode(context, (Command)); Starport.Loan memory loan = close.loan; if (loan.start == block.timestamp || SP.closed(loan.getId())) { revert InvalidLoan(); } bool loanActive = Status(loan.terms.status).isActive(loan, close.extraData); if (close.action == Actions.Repayment && loanActive) { if (fulfiller != getBorrower(loan) && fulfiller != _getApproved(loan.getId())) { revert InvalidRepayer(); } offer = loan.collateral; (SpentItem[] memory payment, SpentItem[] memory carry) = Pricing(loan.terms.pricing).getPaymentConsideration(loan); consideration = StarportLib.mergeSpentItemsToReceivedItems({ payment: payment, paymentRecipient: loan.issuer, carry: carry, carryRecipient: loan.originator }); } else if (close.action == Actions.Settlement && !loanActive) { address authorized; (consideration, authorized) = Settlement(loan.terms.settlement).getSettlementConsideration(loan); if (authorized == address(this)) { revert CustodianCannotBeAuthorized(); } consideration = StarportLib.removeZeroAmountItems(consideration); if (authorized == address(0) || fulfiller == authorized) { offer = loan.collateral; } else if (authorized == loan.terms.settlement || authorized == loan.issuer) {} else { revert InvalidFulfiller(); } } else { revert InvalidAction(); } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev Enables the collateral deposited to be spent via seaport * @param offer The item to make available to seaport */ function _enableAssetWithSeaport(SpentItem memory offer) internal { //approve consideration based on item type if (offer.itemType == ItemType.ERC721) { ERC721(offer.token).approve(seaport, offer.identifier); } else if (offer.itemType == ItemType.ERC1155) { ERC1155(offer.token).setApprovalForAll(seaport, true); } else if (offer.itemType == ItemType.ERC20) { if (ERC20(offer.token).allowance(address(this), seaport) != type(uint256).max) { SafeTransferLib.safeApproveWithRetry(offer.token, seaport, type(uint256).max); } } } /** * @dev Sets approvals for the collateral deposited to be spent via seaport * @param loan The loan being settled */ function _setOfferApprovalsWithSeaport(Starport.Loan memory loan) internal { _beforeApprovalsSetHook(loan); uint256 i = 0; for (; i < loan.collateral.length;) { _enableAssetWithSeaport(loan.collateral[i]); unchecked { ++i; } } } /** * @dev transfers out the collateral to the handler address * @param offer The item to send out of the Custodian * @param authorized The address handling the asset further */ function _transferCollateralAuthorized(SpentItem memory offer, address authorized) internal { // Approve consideration based on item type if (offer.itemType == ItemType.ERC721) { ERC721(offer.token).transferFrom(address(this), authorized, offer.identifier); } else if (offer.itemType == ItemType.ERC1155) { ERC1155(offer.token).safeTransferFrom(address(this), authorized, offer.identifier, offer.amount, ""); } else if (offer.itemType == ItemType.ERC20) { SafeTransferLib.safeTransfer(offer.token, authorized, offer.amount); } } /** * @dev transfers out the collateral of SpentItem to the handler address * @param offer The SpentItem array to send out of the Custodian * @param authorized The address handling the asset further */ function _moveCollateralToAuthorized(SpentItem[] memory offer, address authorized) internal { uint256 i = 0; for (; i < offer.length;) { _transferCollateralAuthorized(offer[i], authorized); unchecked { ++i; } } } /** * @dev settle the loan with Starport * @param loan The the loan that is settled * @param fulfiller The address executing seaport */ function _postSettlementExecute(Starport.Loan memory loan, address fulfiller) internal virtual { _beforeSettlementHandlerHook(loan); if (Settlement(loan.terms.settlement).postSettlement(loan, fulfiller) != Settlement.postSettlement.selector) { revert InvalidPostSettlement(); } _afterSettlementHandlerHook(loan); } /** * @dev settle the loan with Starport * @param loan The the loan that is settled * @param fulfiller The address executing seaport */ function _postRepaymentExecute(Starport.Loan memory loan, address fulfiller) internal virtual { _beforeSettlementHandlerHook(loan); if (Settlement(loan.terms.settlement).postRepayment(loan, fulfiller) != Settlement.postRepayment.selector) { revert InvalidPostRepayment(); } _afterSettlementHandlerHook(loan); } /** * @dev settle the loan with Starport * @param loan The the loan to settle */ function _settleLoan(Starport.Loan memory loan) internal virtual { _beforeSettleLoanHook(loan); uint256 loanId = loan.getId(); if (_exists(loanId)) { _burn(loanId); } SP.settle(loan); _afterSettleLoanHook(loan); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev hook to call before the approvals are set * @param loan The loan being settled */ function _beforeApprovalsSetHook(Starport.Loan memory loan) internal virtual {} /** * @dev Hook to call before the loan get settlement call * @param loan The loan being settled */ function _beforeGetSettlementConsideration(Starport.Loan memory loan) internal virtual {} /** * @dev Hook to call after the loan get settlement call * @param loan The loan being settled */ function _afterGetSettlementConsideration(Starport.Loan memory loan) internal virtual {} /** * @dev Hook to call before the the loan settlement handler execute call * @param loan The loan being settled */ function _beforeSettlementHandlerHook(Starport.Loan memory loan) internal virtual {} /** * @dev Hook to call after the the loan settlement handler execute call * @param loan The loan being settled */ function _afterSettlementHandlerHook(Starport.Loan memory loan) internal virtual {} /** * @dev Hook to call before the loan is settled with the Starport * @param loan The loan being settled */ function _beforeSettleLoanHook(Starport.Loan memory loan) internal virtual {} /** * @dev Hook to call after the loan is settled with the Starport * @param loan The loan being settled */ function _afterSettleLoanHook(Starport.Loan memory loan) internal virtual {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev only allows Starport to execute the function */ modifier onlyStarport() { if (msg.sender != address(SP)) { revert NotStarport(); } _; } /** * @dev only allows seaport to execute the function */ modifier onlySeaport() { if (msg.sender != address(seaport)) { revert NotSeaport(); } _; } }
// SPDX-License-Identifier: BUSL-1.1 // // ↑↑↑↑ ↑↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑ ↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑ ↑↑↑↑ ↑ ↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ Starport: Lending Kernel // ↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑↑↑↑↑ Designed with love by Astaria Labs, Inc // ↑↑↑↑ ↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ pragma solidity ^0.8.17; import {Ownable} from "solady/src/auth/Ownable.sol"; abstract contract PausableNonReentrant is Ownable { uint256 private constant _UNLOCKED = 0x1; uint256 private constant _LOCKED = 0x2; uint256 private constant _PAUSED = 0x3; uint256 private _state = _UNLOCKED; event Paused(); event Unpaused(); error IsPaused(); error IsLocked(); error NotPaused(); /* * @dev modifier to ensure that the contract is not paused or locked */ modifier pausableNonReentrant() { assembly ("memory-safe") { //If locked or paused, handle revert cases if gt(sload(_state.slot), _UNLOCKED) { if gt(sload(_state.slot), _LOCKED) { //Revert IsPaused mstore(0, 0x1309a563) revert(0x1c, 0x04) } //Revert IsLocked mstore(0, 0xcaa30f55) revert(0x1c, 0x04) } sstore(_state.slot, _LOCKED) } _; assembly ("memory-safe") { sstore(_state.slot, _UNLOCKED) } } /* * @dev Pause the contract if not paused or locked */ function pause() external onlyOwner { assembly ("memory-safe") { //If locked, prevent owner from overriding state if eq(sload(_state.slot), _LOCKED) { //Revert IsLocked mstore(0, 0xcaa30f55) revert(0x1c, 0x04) } sstore(_state.slot, _PAUSED) } emit Paused(); } /* * @dev unpause the contract if not paused or locked */ function unpause() external onlyOwner { assembly ("memory-safe") { //If not paused, prevent owner from overriding state if lt(sload(_state.slot), _PAUSED) { //Revert NotPaused mstore(0, 0x6cd60201) revert(0x1c, 0x04) } sstore(_state.slot, _UNLOCKED) } emit Unpaused(); } /* * @dev helper to determine if the contract is paused * @return bool True if the contract is paused, false otherwise */ function paused() external view returns (bool) { return _state == _PAUSED; } }
// SPDX-License-Identifier: BUSL-1.1 // // ↑↑↑↑ ↑↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑ ↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑ ↑↑↑↑ ↑ ↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ Starport: Lending Kernel // ↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑↑↑↑↑ Designed with love by Astaria Labs, Inc // ↑↑↑↑ ↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ pragma solidity ^0.8.17; import {Starport} from "../Starport.sol"; import {AdditionalTransfer} from "../lib/StarportLib.sol"; import {Validation} from "../lib/Validation.sol"; import {SpentItem} from "seaport-types/src/lib/ConsiderationStructs.sol"; abstract contract Pricing is Validation { Starport public immutable SP; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ error InvalidRefinance(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTRUCTOR */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ constructor(Starport SP_) { SP = SP_; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev computes the payment details for a loan * @param loan The loan to compute the payment details for */ function getPaymentConsideration(Starport.Loan calldata loan) public view virtual returns (SpentItem[] memory, SpentItem[] memory); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev computes the refinance details for a loan * @param loan The loan to compute the payment details for * @param newPricingData The new pricing data being offered * @param fulfiller The address of the fulfiller */ function getRefinanceConsideration(Starport.Loan calldata loan, bytes calldata newPricingData, address fulfiller) external view virtual returns (SpentItem[] memory, SpentItem[] memory, AdditionalTransfer[] memory); }
// SPDX-License-Identifier: BUSL-1.1 // // ↑↑↑↑ ↑↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑ ↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑ ↑↑↑↑ ↑ ↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ Starport: Lending Kernel // ↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑↑↑↑↑ Designed with love by Astaria Labs, Inc // ↑↑↑↑ ↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ pragma solidity ^0.8.17; import {Starport} from "../Starport.sol"; import {Validation} from "../lib/Validation.sol"; abstract contract Status is Validation { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /* * @dev Returns true if the loan is still active, false otherwise. * @param loan The loan to check. * @param extraData Additional data to be used in the status check. * @return bool True if the loan is still active, false otherwise. */ function isActive(Starport.Loan calldata loan, bytes calldata extraData) external view virtual returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 // // ↑↑↑↑ ↑↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑ ↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑ ↑↑↑↑ ↑ ↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ Starport: Lending Kernel // ↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑↑↑↑↑ Designed with love by Astaria Labs, Inc // ↑↑↑↑ ↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ pragma solidity ^0.8.17; import {Starport} from "../Starport.sol"; import {Validation} from "../lib/Validation.sol"; import {ReceivedItem} from "seaport-types/src/lib/ConsiderationStructs.sol"; abstract contract Settlement is Validation { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS AND IMMUTABLES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ Starport public immutable SP; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTRUCTOR */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ constructor(Starport SP_) { SP = SP_; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /* * @dev Called by the Custodian after a loan has been settled * @param loan The loan that has been settled * @param fulfiller The address of the fulfiller */ function postSettlement(Starport.Loan calldata loan, address fulfiller) external virtual returns (bytes4); /* * @dev Called by the Starport/Custodian after a loan has been repaid * @param loan The loan that has been settled * @param fulfiller The address of the fulfiller */ function postRepayment(Starport.Loan calldata loan, address fulfiller) external virtual returns (bytes4); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /* * @dev helper to get the consideration for a loan * @param loan The loan in question * @return consideration The settlement consideration for the loan * @return address The address of the authorized party (if any) */ function getSettlementConsideration(Starport.Loan calldata loan) public view virtual returns (ReceivedItem[] memory consideration, address authorized); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* FUNCTION OVERRIDES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /* * @dev standard erc1155 received hook */ function onERC1155Received(address, address, uint256, uint256, bytes calldata) external view returns (bytes4) { return this.onERC1155Received.selector; } }
// SPDX-License-Identifier: BUSL-1.1 // // ↑↑↑↑ ↑↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑ ↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑ ↑↑↑↑ ↑ ↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ Starport: Lending Kernel // ↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑↑↑↑↑ Designed with love by Astaria Labs, Inc // ↑↑↑↑ ↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ pragma solidity ^0.8.17; import {Starport} from "../Starport.sol"; import {ItemType, ReceivedItem, SpentItem} from "seaport-types/src/lib/ConsiderationStructs.sol"; import {ERC721} from "solady/src/tokens/ERC721.sol"; import {ERC20} from "solady/src/tokens/ERC20.sol"; import {ERC1155} from "solady/src/tokens/ERC1155.sol"; import {SafeTransferLib} from "solady/src/utils/SafeTransferLib.sol"; import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol"; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* LIB ENUMS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ enum Actions { Nothing, Repayment, Settlement } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* LIB STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ struct AdditionalTransfer { ItemType itemType; address token; address from; address to; uint256 identifier; uint256 amount; } library StarportLib { using FixedPointMathLib for uint256; using FixedPointMathLib for int256; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ error InvalidSalt(); error InvalidItemAmount(); error NativeAssetsNotSupported(); error InvalidItemTokenNoCode(); error InvalidItemIdentifier(); // Must be zero for ERC20's error InvalidItemType(); error InvalidTransferLength(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS AND IMMUTABLES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ uint256 internal constant _INVALID_SALT = 0x81e69d9b00000000000000000000000000000000000000000000000000000000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function calculateSimpleInterest(uint256 delta_t, uint256 amount, uint256 rate, uint256 decimals) public pure returns (uint256) { return (((delta_t * rate) * amount) / 10 ** decimals) / 365 days; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function getId(Starport.Loan memory loan) internal pure returns (uint256 loanId) { loanId = uint256(keccak256(abi.encode(loan))); } function validateSalt( mapping(address => mapping(bytes32 => bool)) storage usedSalts, address validator, bytes32 salt ) internal { assembly ("memory-safe") { mstore(0x0, validator) mstore(0x20, usedSalts.slot) // usedSalts[borrower] mstore(0x20, keccak256(0x0, 0x40)) mstore(0x0, salt) // usedSalts[borrower][salt] let loc := keccak256(0x0, 0x40) // if (usedSalts[borrower][salt] == true) if iszero(iszero(sload(loc))) { // revert InvalidSalt() mstore(0x0, _INVALID_SALT) revert(0x0, 0x04) } sstore(loc, 1) } } /** * @dev Merges an array of SpentItems into ReceivedItems * @param payment The SpentItem[] for payment * @param paymentRecipient The recipient address of the payment * @param carry The SpentItem[] for carry * @param carryRecipient The recipient address of the carry * @return consideration An array of ReceivedItems */ function mergeSpentItemsToReceivedItems( SpentItem[] memory payment, address paymentRecipient, SpentItem[] memory carry, address carryRecipient ) internal pure returns (ReceivedItem[] memory consideration) { consideration = new ReceivedItem[](payment.length + carry.length); uint256 i = 0; uint256 j = 0; for (; i < payment.length;) { if (payment[i].amount > 0) { SpentItem memory paymentItem = payment[i]; consideration[j] = ReceivedItem({ itemType: paymentItem.itemType, identifier: paymentItem.identifier, amount: paymentItem.amount, token: paymentItem.token, recipient: payable(paymentRecipient) }); unchecked { ++j; } } unchecked { ++i; } } if (carry.length > 0) { i = 0; for (; i < carry.length;) { if (carry[i].amount > 0) { SpentItem memory carryItem = carry[i]; consideration[j] = ReceivedItem({ itemType: carryItem.itemType, identifier: carryItem.identifier, amount: carryItem.amount, token: carryItem.token, recipient: payable(carryRecipient) }); unchecked { ++j; } } unchecked { ++i; } } } assembly ("memory-safe") { mstore(consideration, j) } } /** * @dev Removes ReceivedItems with zero amounts * @param consideration The ReceivedItem[] for payment * @return newConsideration An array of ReceivedItems with zero amounts removed */ function removeZeroAmountItems(ReceivedItem[] memory consideration) internal pure returns (ReceivedItem[] memory newConsideration) { uint256 j = 0; newConsideration = new ReceivedItem[](consideration.length); for (uint256 i = 0; i < consideration.length;) { if (consideration[i].amount > 0) { ReceivedItem memory considerationItem = consideration[i]; newConsideration[j] = ReceivedItem({ itemType: considerationItem.itemType, identifier: considerationItem.identifier, amount: considerationItem.amount, token: considerationItem.token, recipient: considerationItem.recipient }); unchecked { ++j; } } unchecked { ++i; } } assembly ("memory-safe") { mstore(newConsideration, j) } } function transferAdditionalTransfersCalldata(AdditionalTransfer[] calldata transfers) internal { uint256 i = 0; for (; i < transfers.length;) { AdditionalTransfer calldata transfer = transfers[i]; if (transfer.token.code.length == 0) { revert InvalidItemTokenNoCode(); } if (transfer.itemType == ItemType.ERC20) { // erc20 transfer if (transfer.amount > 0) { SafeTransferLib.safeTransferFrom(transfer.token, transfer.from, transfer.to, transfer.amount); } } else if (transfer.itemType == ItemType.ERC721) { // erc721 transfer ERC721(transfer.token).transferFrom(transfer.from, transfer.to, transfer.identifier); } else if (transfers[i].itemType == ItemType.ERC1155) { // erc1155 transfer if (transfer.amount > 0) { ERC1155(transfer.token).safeTransferFrom( transfer.from, transfer.to, transfer.identifier, transfer.amount, "" ); } } else { revert NativeAssetsNotSupported(); } unchecked { ++i; } } } function transferAdditionalTransfers(AdditionalTransfer[] memory transfers) internal { uint256 i = 0; for (; i < transfers.length;) { AdditionalTransfer memory transfer = transfers[i]; if (transfer.token.code.length == 0) { revert InvalidItemTokenNoCode(); } if (transfer.itemType == ItemType.ERC20) { // erc20 transfer if (transfer.amount > 0) { SafeTransferLib.safeTransferFrom(transfer.token, transfer.from, transfer.to, transfer.amount); } } else if (transfer.itemType == ItemType.ERC721) { // erc721 transfer ERC721(transfer.token).transferFrom(transfer.from, transfer.to, transfer.identifier); } else if (transfer.itemType == ItemType.ERC1155) { // erc1155 transfer if (transfer.amount > 0) { ERC1155(transfer.token).safeTransferFrom( transfer.from, transfer.to, transfer.identifier, transfer.amount, "" ); } } else { revert NativeAssetsNotSupported(); } unchecked { ++i; } } } function transferSpentItems(SpentItem[] memory transfers, address from, address to, bool safe) internal { if (transfers.length > 0) { uint256 i = 0; for (; i < transfers.length;) { SpentItem memory transfer = transfers[i]; _transferItem(transfer.itemType, transfer.token, transfer.identifier, transfer.amount, from, to, safe); unchecked { ++i; } } } else { revert InvalidTransferLength(); } } function transferSpentItemsSelf(SpentItem[] memory transfers, address to) internal { if (transfers.length > 0) { uint256 i = 0; for (; i < transfers.length;) { SpentItem memory transfer = transfers[i]; _transferItem( transfer.itemType, transfer.token, transfer.identifier, transfer.amount, address(this), to ); unchecked { ++i; } } } else { revert InvalidTransferLength(); } } function _transferItem( ItemType itemType, address token, uint256 identifier, uint256 amount, address from, address to, bool safe ) internal { if (token.code.length == 0) { revert InvalidItemTokenNoCode(); } if (itemType == ItemType.ERC20) { if (identifier > 0 && safe) { revert InvalidItemIdentifier(); } if (amount == 0 && safe) { revert InvalidItemAmount(); } SafeTransferLib.safeTransferFrom(token, from, to, amount); } else if (itemType == ItemType.ERC721) { if (amount != 1 && safe) { revert InvalidItemAmount(); } // erc721 transfer ERC721(token).transferFrom(from, to, identifier); } else if (itemType == ItemType.ERC1155) { if (amount == 0 && safe) { revert InvalidItemAmount(); } // erc1155 transfer ERC1155(token).safeTransferFrom(from, to, identifier, amount, ""); } else { revert InvalidItemType(); } } function _transferItem( ItemType itemType, address token, uint256 identifier, uint256 amount, address from, address to ) internal { if (token.code.length == 0) { revert InvalidItemTokenNoCode(); } if (itemType == ItemType.ERC20) { SafeTransferLib.safeTransfer(token, to, amount); } else if (itemType == ItemType.ERC721) { // erc721 transfer ERC721(token).transferFrom(from, to, identifier); } else if (itemType == ItemType.ERC1155) { // erc1155 transfer ERC1155(token).safeTransferFrom(from, to, identifier, amount, ""); } else { revert InvalidItemType(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { BasicOrderType, ItemType, OrderType, Side } from "./ConsiderationEnums.sol"; import { CalldataPointer, MemoryPointer } from "../helpers/PointerLibraries.sol"; /** * @dev An order contains eleven components: an offerer, a zone (or account that * can cancel the order or restrict who can fulfill the order depending on * the type), the order type (specifying partial fill support as well as * restricted order status), the start and end time, a hash that will be * provided to the zone when validating restricted orders, a salt, a key * corresponding to a given conduit, a counter, and an arbitrary number of * offer items that can be spent along with consideration items that must * be received by their respective recipient. */ struct OrderComponents { address offerer; address zone; OfferItem[] offer; ConsiderationItem[] consideration; OrderType orderType; uint256 startTime; uint256 endTime; bytes32 zoneHash; uint256 salt; bytes32 conduitKey; uint256 counter; } /** * @dev An offer item has five components: an item type (ETH or other native * tokens, ERC20, ERC721, and ERC1155, as well as criteria-based ERC721 and * ERC1155), a token address, a dual-purpose "identifierOrCriteria" * component that will either represent a tokenId or a merkle root * depending on the item type, and a start and end amount that support * increasing or decreasing amounts over the duration of the respective * order. */ struct OfferItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; } /** * @dev A consideration item has the same five components as an offer item and * an additional sixth component designating the required recipient of the * item. */ struct ConsiderationItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; address payable recipient; } /** * @dev A spent item is translated from a utilized offer item and has four * components: an item type (ETH or other native tokens, ERC20, ERC721, and * ERC1155), a token address, a tokenId, and an amount. */ struct SpentItem { ItemType itemType; address token; uint256 identifier; uint256 amount; } /** * @dev A received item is translated from a utilized consideration item and has * the same four components as a spent item, as well as an additional fifth * component designating the required recipient of the item. */ struct ReceivedItem { ItemType itemType; address token; uint256 identifier; uint256 amount; address payable recipient; } /** * @dev For basic orders involving ETH / native / ERC20 <=> ERC721 / ERC1155 * matching, a group of six functions may be called that only requires a * subset of the usual order arguments. Note the use of a "basicOrderType" * enum; this represents both the usual order type as well as the "route" * of the basic order (a simple derivation function for the basic order * type is `basicOrderType = orderType + (4 * basicOrderRoute)`.) */ struct BasicOrderParameters { // calldata offset address considerationToken; // 0x24 uint256 considerationIdentifier; // 0x44 uint256 considerationAmount; // 0x64 address payable offerer; // 0x84 address zone; // 0xa4 address offerToken; // 0xc4 uint256 offerIdentifier; // 0xe4 uint256 offerAmount; // 0x104 BasicOrderType basicOrderType; // 0x124 uint256 startTime; // 0x144 uint256 endTime; // 0x164 bytes32 zoneHash; // 0x184 uint256 salt; // 0x1a4 bytes32 offererConduitKey; // 0x1c4 bytes32 fulfillerConduitKey; // 0x1e4 uint256 totalOriginalAdditionalRecipients; // 0x204 AdditionalRecipient[] additionalRecipients; // 0x224 bytes signature; // 0x244 // Total length, excluding dynamic array data: 0x264 (580) } /** * @dev Basic orders can supply any number of additional recipients, with the * implied assumption that they are supplied from the offered ETH (or other * native token) or ERC20 token for the order. */ struct AdditionalRecipient { uint256 amount; address payable recipient; } /** * @dev The full set of order components, with the exception of the counter, * must be supplied when fulfilling more sophisticated orders or groups of * orders. The total number of original consideration items must also be * supplied, as the caller may specify additional consideration items. */ struct OrderParameters { address offerer; // 0x00 address zone; // 0x20 OfferItem[] offer; // 0x40 ConsiderationItem[] consideration; // 0x60 OrderType orderType; // 0x80 uint256 startTime; // 0xa0 uint256 endTime; // 0xc0 bytes32 zoneHash; // 0xe0 uint256 salt; // 0x100 bytes32 conduitKey; // 0x120 uint256 totalOriginalConsiderationItems; // 0x140 // offer.length // 0x160 } /** * @dev Orders require a signature in addition to the other order parameters. */ struct Order { OrderParameters parameters; bytes signature; } /** * @dev Advanced orders include a numerator (i.e. a fraction to attempt to fill) * and a denominator (the total size of the order) in addition to the * signature and other order parameters. It also supports an optional field * for supplying extra data; this data will be provided to the zone if the * order type is restricted and the zone is not the caller, or will be * provided to the offerer as context for contract order types. */ struct AdvancedOrder { OrderParameters parameters; uint120 numerator; uint120 denominator; bytes signature; bytes extraData; } /** * @dev Orders can be validated (either explicitly via `validate`, or as a * consequence of a full or partial fill), specifically cancelled (they can * also be cancelled in bulk via incrementing a per-zone counter), and * partially or fully filled (with the fraction filled represented by a * numerator and denominator). */ struct OrderStatus { bool isValidated; bool isCancelled; uint120 numerator; uint120 denominator; } /** * @dev A criteria resolver specifies an order, side (offer vs. consideration), * and item index. It then provides a chosen identifier (i.e. tokenId) * alongside a merkle proof demonstrating the identifier meets the required * criteria. */ struct CriteriaResolver { uint256 orderIndex; Side side; uint256 index; uint256 identifier; bytes32[] criteriaProof; } /** * @dev A fulfillment is applied to a group of orders. It decrements a series of * offer and consideration items, then generates a single execution * element. A given fulfillment can be applied to as many offer and * consideration items as desired, but must contain at least one offer and * at least one consideration that match. The fulfillment must also remain * consistent on all key parameters across all offer items (same offerer, * token, type, tokenId, and conduit preference) as well as across all * consideration items (token, type, tokenId, and recipient). */ struct Fulfillment { FulfillmentComponent[] offerComponents; FulfillmentComponent[] considerationComponents; } /** * @dev Each fulfillment component contains one index referencing a specific * order and another referencing a specific offer or consideration item. */ struct FulfillmentComponent { uint256 orderIndex; uint256 itemIndex; } /** * @dev An execution is triggered once all consideration items have been zeroed * out. It sends the item in question from the offerer to the item's * recipient, optionally sourcing approvals from either this contract * directly or from the offerer's chosen conduit if one is specified. An * execution is not provided as an argument, but rather is derived via * orders, criteria resolvers, and fulfillments (where the total number of * executions will be less than or equal to the total number of indicated * fulfillments) and returned as part of `matchOrders`. */ struct Execution { ReceivedItem item; address offerer; bytes32 conduitKey; } /** * @dev Restricted orders are validated post-execution by calling validateOrder * on the zone. This struct provides context about the order fulfillment * and any supplied extraData, as well as all order hashes fulfilled in a * call to a match or fulfillAvailable method. */ struct ZoneParameters { bytes32 orderHash; address fulfiller; address offerer; SpentItem[] offer; ReceivedItem[] consideration; bytes extraData; bytes32[] orderHashes; uint256 startTime; uint256 endTime; bytes32 zoneHash; } /** * @dev Zones and contract offerers can communicate which schemas they implement * along with any associated metadata related to each schema. */ struct Schema { uint256 id; bytes metadata; } using StructPointers for OrderComponents global; using StructPointers for OfferItem global; using StructPointers for ConsiderationItem global; using StructPointers for SpentItem global; using StructPointers for ReceivedItem global; using StructPointers for BasicOrderParameters global; using StructPointers for AdditionalRecipient global; using StructPointers for OrderParameters global; using StructPointers for Order global; using StructPointers for AdvancedOrder global; using StructPointers for OrderStatus global; using StructPointers for CriteriaResolver global; using StructPointers for Fulfillment global; using StructPointers for FulfillmentComponent global; using StructPointers for Execution global; using StructPointers for ZoneParameters global; /** * @dev This library provides a set of functions for converting structs to * pointers. */ library StructPointers { /** * @dev Get a MemoryPointer from OrderComponents. * * @param obj The OrderComponents object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OrderComponents memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OrderComponents. * * @param obj The OrderComponents object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OrderComponents calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from OfferItem. * * @param obj The OfferItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OfferItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OfferItem. * * @param obj The OfferItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OfferItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from ConsiderationItem. * * @param obj The ConsiderationItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( ConsiderationItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from ConsiderationItem. * * @param obj The ConsiderationItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( ConsiderationItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from SpentItem. * * @param obj The SpentItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( SpentItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from SpentItem. * * @param obj The SpentItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( SpentItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from ReceivedItem. * * @param obj The ReceivedItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( ReceivedItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from ReceivedItem. * * @param obj The ReceivedItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( ReceivedItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from BasicOrderParameters. * * @param obj The BasicOrderParameters object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( BasicOrderParameters memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from BasicOrderParameters. * * @param obj The BasicOrderParameters object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( BasicOrderParameters calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from AdditionalRecipient. * * @param obj The AdditionalRecipient object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( AdditionalRecipient memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from AdditionalRecipient. * * @param obj The AdditionalRecipient object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( AdditionalRecipient calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from OrderParameters. * * @param obj The OrderParameters object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OrderParameters memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OrderParameters. * * @param obj The OrderParameters object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OrderParameters calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from Order. * * @param obj The Order object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( Order memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from Order. * * @param obj The Order object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( Order calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from AdvancedOrder. * * @param obj The AdvancedOrder object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( AdvancedOrder memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from AdvancedOrder. * * @param obj The AdvancedOrder object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( AdvancedOrder calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from OrderStatus. * * @param obj The OrderStatus object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OrderStatus memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OrderStatus. * * @param obj The OrderStatus object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OrderStatus calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from CriteriaResolver. * * @param obj The CriteriaResolver object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( CriteriaResolver memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from CriteriaResolver. * * @param obj The CriteriaResolver object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( CriteriaResolver calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from Fulfillment. * * @param obj The Fulfillment object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( Fulfillment memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from Fulfillment. * * @param obj The Fulfillment object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( Fulfillment calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from FulfillmentComponent. * * @param obj The FulfillmentComponent object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( FulfillmentComponent memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from FulfillmentComponent. * * @param obj The FulfillmentComponent object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( FulfillmentComponent calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from Execution. * * @param obj The Execution object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( Execution memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from Execution. * * @param obj The Execution object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( Execution calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from ZoneParameters. * * @param obj The ZoneParameters object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( ZoneParameters memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from ZoneParameters. * * @param obj The ZoneParameters object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( ZoneParameters calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC20 + EIP-2612 implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC20.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol) /// /// @dev Note: /// - The ERC20 standard allows minting and transferring to and from the zero address, /// minting and transferring zero tokens, as well as self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. /// - The `permit` function uses the ecrecover precompile (0x1). /// /// If you are overriding: /// - NEVER violate the ERC20 invariant: /// the total sum of all balances must be equal to `totalSupply()`. /// - Check that the overridden function is actually used in the function you want to /// change the behavior of. Much of the code has been manually inlined for performance. abstract contract ERC20 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The total supply has overflowed. error TotalSupplyOverflow(); /// @dev The allowance has overflowed. error AllowanceOverflow(); /// @dev The allowance has underflowed. error AllowanceUnderflow(); /// @dev Insufficient balance. error InsufficientBalance(); /// @dev Insufficient allowance. error InsufficientAllowance(); /// @dev The permit is invalid. error InvalidPermit(); /// @dev The permit has expired. error PermitExpired(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when `amount` tokens is transferred from `from` to `to`. event Transfer(address indexed from, address indexed to, uint256 amount); /// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`. event Approval(address indexed owner, address indexed spender, uint256 amount); /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`. uint256 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`. uint256 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The storage slot for the total supply. uint256 private constant _TOTAL_SUPPLY_SLOT = 0x05345cdf77eb68f44c; /// @dev The balance slot of `owner` is given by: /// ``` /// mstore(0x0c, _BALANCE_SLOT_SEED) /// mstore(0x00, owner) /// let balanceSlot := keccak256(0x0c, 0x20) /// ``` uint256 private constant _BALANCE_SLOT_SEED = 0x87a211a2; /// @dev The allowance slot of (`owner`, `spender`) is given by: /// ``` /// mstore(0x20, spender) /// mstore(0x0c, _ALLOWANCE_SLOT_SEED) /// mstore(0x00, owner) /// let allowanceSlot := keccak256(0x0c, 0x34) /// ``` uint256 private constant _ALLOWANCE_SLOT_SEED = 0x7f5e9f20; /// @dev The nonce slot of `owner` is given by: /// ``` /// mstore(0x0c, _NONCES_SLOT_SEED) /// mstore(0x00, owner) /// let nonceSlot := keccak256(0x0c, 0x20) /// ``` uint256 private constant _NONCES_SLOT_SEED = 0x38377508; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev `(_NONCES_SLOT_SEED << 16) | 0x1901`. uint256 private constant _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX = 0x383775081901; /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`. bytes32 private constant _DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; /// @dev `keccak256("1")`. bytes32 private constant _VERSION_HASH = 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6; /// @dev `keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")`. bytes32 private constant _PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the name of the token. function name() public view virtual returns (string memory); /// @dev Returns the symbol of the token. function symbol() public view virtual returns (string memory); /// @dev Returns the decimals places of the token. function decimals() public view virtual returns (uint8) { return 18; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the amount of tokens in existence. function totalSupply() public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { result := sload(_TOTAL_SUPPLY_SLOT) } } /// @dev Returns the amount of tokens owned by `owner`. function balanceOf(address owner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { mstore(0x0c, _BALANCE_SLOT_SEED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x20)) } } /// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`. function allowance(address owner, address spender) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, spender) mstore(0x0c, _ALLOWANCE_SLOT_SEED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x34)) } } /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens. /// /// Emits a {Approval} event. function approve(address spender, uint256 amount) public virtual returns (bool) { /// @solidity memory-safe-assembly assembly { // Compute the allowance slot and store the amount. mstore(0x20, spender) mstore(0x0c, _ALLOWANCE_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x34), amount) // Emit the {Approval} event. mstore(0x00, amount) log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c))) } return true; } /// @dev Transfer `amount` tokens from the caller to `to`. /// /// Requirements: /// - `from` must at least have `amount`. /// /// Emits a {Transfer} event. function transfer(address to, uint256 amount) public virtual returns (bool) { _beforeTokenTransfer(msg.sender, to, amount); /// @solidity memory-safe-assembly assembly { // Compute the balance slot and load its value. mstore(0x0c, _BALANCE_SLOT_SEED) mstore(0x00, caller()) let fromBalanceSlot := keccak256(0x0c, 0x20) let fromBalance := sload(fromBalanceSlot) // Revert if insufficient balance. if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } // Subtract and store the updated balance. sstore(fromBalanceSlot, sub(fromBalance, amount)) // Compute the balance slot of `to`. mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x20) // Add and store the updated balance of `to`. // Will not overflow because the sum of all user balances // cannot exceed the maximum uint256 value. sstore(toBalanceSlot, add(sload(toBalanceSlot), amount)) // Emit the {Transfer} event. mstore(0x20, amount) log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c))) } _afterTokenTransfer(msg.sender, to, amount); return true; } /// @dev Transfers `amount` tokens from `from` to `to`. /// /// Note: Does not update the allowance if it is the maximum uint256 value. /// /// Requirements: /// - `from` must at least have `amount`. /// - The caller must have at least `amount` of allowance to transfer the tokens of `from`. /// /// Emits a {Transfer} event. function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) { _beforeTokenTransfer(from, to, amount); /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) // Compute the allowance slot and load its value. mstore(0x20, caller()) mstore(0x0c, or(from_, _ALLOWANCE_SLOT_SEED)) let allowanceSlot := keccak256(0x0c, 0x34) let allowance_ := sload(allowanceSlot) // If the allowance is not the maximum uint256 value. if add(allowance_, 1) { // Revert if the amount to be transferred exceeds the allowance. if gt(amount, allowance_) { mstore(0x00, 0x13be252b) // `InsufficientAllowance()`. revert(0x1c, 0x04) } // Subtract and store the updated allowance. sstore(allowanceSlot, sub(allowance_, amount)) } // Compute the balance slot and load its value. mstore(0x0c, or(from_, _BALANCE_SLOT_SEED)) let fromBalanceSlot := keccak256(0x0c, 0x20) let fromBalance := sload(fromBalanceSlot) // Revert if insufficient balance. if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } // Subtract and store the updated balance. sstore(fromBalanceSlot, sub(fromBalance, amount)) // Compute the balance slot of `to`. mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x20) // Add and store the updated balance of `to`. // Will not overflow because the sum of all user balances // cannot exceed the maximum uint256 value. sstore(toBalanceSlot, add(sload(toBalanceSlot), amount)) // Emit the {Transfer} event. mstore(0x20, amount) log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c))) } _afterTokenTransfer(from, to, amount); return true; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EIP-2612 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev For more performance, override to return the constant value /// of `keccak256(bytes(name()))` if `name()` will never change. function _constantNameHash() internal view virtual returns (bytes32 result) {} /// @dev Returns the current nonce for `owner`. /// This value is used to compute the signature for EIP-2612 permit. function nonces(address owner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the nonce slot and load its value. mstore(0x0c, _NONCES_SLOT_SEED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x20)) } } /// @dev Sets `value` as the allowance of `spender` over the tokens of `owner`, /// authorized by a signed approval by `owner`. /// /// Emits a {Approval} event. function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { bytes32 nameHash = _constantNameHash(); // We simply calculate it on-the-fly to allow for cases where the `name` may change. if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name())); /// @solidity memory-safe-assembly assembly { // Revert if the block timestamp is greater than `deadline`. if gt(timestamp(), deadline) { mstore(0x00, 0x1a15a3cc) // `PermitExpired()`. revert(0x1c, 0x04) } let m := mload(0x40) // Grab the free memory pointer. // Clean the upper 96 bits. owner := shr(96, shl(96, owner)) spender := shr(96, shl(96, spender)) // Compute the nonce slot and load its value. mstore(0x0e, _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX) mstore(0x00, owner) let nonceSlot := keccak256(0x0c, 0x20) let nonceValue := sload(nonceSlot) // Prepare the domain separator. mstore(m, _DOMAIN_TYPEHASH) mstore(add(m, 0x20), nameHash) mstore(add(m, 0x40), _VERSION_HASH) mstore(add(m, 0x60), chainid()) mstore(add(m, 0x80), address()) mstore(0x2e, keccak256(m, 0xa0)) // Prepare the struct hash. mstore(m, _PERMIT_TYPEHASH) mstore(add(m, 0x20), owner) mstore(add(m, 0x40), spender) mstore(add(m, 0x60), value) mstore(add(m, 0x80), nonceValue) mstore(add(m, 0xa0), deadline) mstore(0x4e, keccak256(m, 0xc0)) // Prepare the ecrecover calldata. mstore(0x00, keccak256(0x2c, 0x42)) mstore(0x20, and(0xff, v)) mstore(0x40, r) mstore(0x60, s) let t := staticcall(gas(), 1, 0, 0x80, 0x20, 0x20) // If the ecrecover fails, the returndatasize will be 0x00, // `owner` will be checked if it equals the hash at 0x00, // which evaluates to false (i.e. 0), and we will revert. // If the ecrecover succeeds, the returndatasize will be 0x20, // `owner` will be compared against the returned address at 0x20. if iszero(eq(mload(returndatasize()), owner)) { mstore(0x00, 0xddafbaef) // `InvalidPermit()`. revert(0x1c, 0x04) } // Increment and store the updated nonce. sstore(nonceSlot, add(nonceValue, t)) // `t` is 1 if ecrecover succeeds. // Compute the allowance slot and store the value. // The `owner` is already at slot 0x20. mstore(0x40, or(shl(160, _ALLOWANCE_SLOT_SEED), spender)) sstore(keccak256(0x2c, 0x34), value) // Emit the {Approval} event. log3(add(m, 0x60), 0x20, _APPROVAL_EVENT_SIGNATURE, owner, spender) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero pointer. } } /// @dev Returns the EIP-712 domain separator for the EIP-2612 permit. function DOMAIN_SEPARATOR() public view virtual returns (bytes32 result) { bytes32 nameHash = _constantNameHash(); // We simply calculate it on-the-fly to allow for cases where the `name` may change. if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name())); /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Grab the free memory pointer. mstore(m, _DOMAIN_TYPEHASH) mstore(add(m, 0x20), nameHash) mstore(add(m, 0x40), _VERSION_HASH) mstore(add(m, 0x60), chainid()) mstore(add(m, 0x80), address()) result := keccak256(m, 0xa0) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints `amount` tokens to `to`, increasing the total supply. /// /// Emits a {Transfer} event. function _mint(address to, uint256 amount) internal virtual { _beforeTokenTransfer(address(0), to, amount); /// @solidity memory-safe-assembly assembly { let totalSupplyBefore := sload(_TOTAL_SUPPLY_SLOT) let totalSupplyAfter := add(totalSupplyBefore, amount) // Revert if the total supply overflows. if lt(totalSupplyAfter, totalSupplyBefore) { mstore(0x00, 0xe5cfe957) // `TotalSupplyOverflow()`. revert(0x1c, 0x04) } // Store the updated total supply. sstore(_TOTAL_SUPPLY_SLOT, totalSupplyAfter) // Compute the balance slot and load its value. mstore(0x0c, _BALANCE_SLOT_SEED) mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x20) // Add and store the updated balance. sstore(toBalanceSlot, add(sload(toBalanceSlot), amount)) // Emit the {Transfer} event. mstore(0x20, amount) log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, mload(0x0c))) } _afterTokenTransfer(address(0), to, amount); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Burns `amount` tokens from `from`, reducing the total supply. /// /// Emits a {Transfer} event. function _burn(address from, uint256 amount) internal virtual { _beforeTokenTransfer(from, address(0), amount); /// @solidity memory-safe-assembly assembly { // Compute the balance slot and load its value. mstore(0x0c, _BALANCE_SLOT_SEED) mstore(0x00, from) let fromBalanceSlot := keccak256(0x0c, 0x20) let fromBalance := sload(fromBalanceSlot) // Revert if insufficient balance. if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } // Subtract and store the updated balance. sstore(fromBalanceSlot, sub(fromBalance, amount)) // Subtract and store the updated total supply. sstore(_TOTAL_SUPPLY_SLOT, sub(sload(_TOTAL_SUPPLY_SLOT), amount)) // Emit the {Transfer} event. mstore(0x00, amount) log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0) } _afterTokenTransfer(from, address(0), amount); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Moves `amount` of tokens from `from` to `to`. function _transfer(address from, address to, uint256 amount) internal virtual { _beforeTokenTransfer(from, to, amount); /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) // Compute the balance slot and load its value. mstore(0x0c, or(from_, _BALANCE_SLOT_SEED)) let fromBalanceSlot := keccak256(0x0c, 0x20) let fromBalance := sload(fromBalanceSlot) // Revert if insufficient balance. if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } // Subtract and store the updated balance. sstore(fromBalanceSlot, sub(fromBalance, amount)) // Compute the balance slot of `to`. mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x20) // Add and store the updated balance of `to`. // Will not overflow because the sum of all user balances // cannot exceed the maximum uint256 value. sstore(toBalanceSlot, add(sload(toBalanceSlot), amount)) // Emit the {Transfer} event. mstore(0x20, amount) log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c))) } _afterTokenTransfer(from, to, amount); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL ALLOWANCE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Updates the allowance of `owner` for `spender` based on spent `amount`. function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { /// @solidity memory-safe-assembly assembly { // Compute the allowance slot and load its value. mstore(0x20, spender) mstore(0x0c, _ALLOWANCE_SLOT_SEED) mstore(0x00, owner) let allowanceSlot := keccak256(0x0c, 0x34) let allowance_ := sload(allowanceSlot) // If the allowance is not the maximum uint256 value. if add(allowance_, 1) { // Revert if the amount to be transferred exceeds the allowance. if gt(amount, allowance_) { mstore(0x00, 0x13be252b) // `InsufficientAllowance()`. revert(0x1c, 0x04) } // Subtract and store the updated allowance. sstore(allowanceSlot, sub(allowance_, amount)) } } } /// @dev Sets `amount` as the allowance of `spender` over the tokens of `owner`. /// /// Emits a {Approval} event. function _approve(address owner, address spender, uint256 amount) internal virtual { /// @solidity memory-safe-assembly assembly { let owner_ := shl(96, owner) // Compute the allowance slot and store the amount. mstore(0x20, spender) mstore(0x0c, or(owner_, _ALLOWANCE_SLOT_SEED)) sstore(keccak256(0x0c, 0x34), amount) // Emit the {Approval} event. mstore(0x00, amount) log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, owner_), shr(96, mload(0x2c))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS TO OVERRIDE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Hook that is called before any transfer of tokens. /// This includes minting and burning. function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /// @dev Hook that is called after any transfer of tokens. /// This includes minting and burning. function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) library FixedPointMathLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The operation failed, as the output exceeds the maximum value of uint256. error ExpOverflow(); /// @dev The operation failed, as the output exceeds the maximum value of uint256. error FactorialOverflow(); /// @dev The operation failed, due to an overflow. error RPowOverflow(); /// @dev The mantissa is too big to fit. error MantissaOverflow(); /// @dev The operation failed, due to an multiplication overflow. error MulWadFailed(); /// @dev The operation failed, due to an multiplication overflow. error SMulWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error DivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error SDivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error MulDivFailed(); /// @dev The division failed, as the denominator is zero. error DivFailed(); /// @dev The full precision multiply-divide operation failed, either due /// to the result being larger than 256 bits, or a division by a zero. error FullMulDivFailed(); /// @dev The output is undefined, as the input is less-than-or-equal to zero. error LnWadUndefined(); /// @dev The input outside the acceptable domain. error OutOfDomain(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The scalar of ETH and most ERC20s. uint256 internal constant WAD = 1e18; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIMPLIFIED FIXED POINT OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `(x * y) / WAD` rounded down. function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if mul(y, gt(x, div(not(0), y))) { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down. function sMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`. if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) { mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`. revert(0x1c, 0x04) } z := sdiv(z, WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded up. function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if mul(y, gt(x, div(not(0), y))) { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD)) } } /// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks. function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD)) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`. if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function sDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, WAD) // Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`. if iszero(and(iszero(iszero(y)), eq(sdiv(z, WAD), x))) { mstore(0x00, 0x5c43740d) // `SDivWadFailed()`. revert(0x1c, 0x04) } z := sdiv(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded up. function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`. if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks. function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `x` to the power of `y`. /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`. function powWad(int256 x, int256 y) internal pure returns (int256) { // Using `ln(x)` means `x` must be greater than 0. return expWad((lnWad(x) * y) / int256(WAD)); } /// @dev Returns `exp(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/21/exp-ln function expWad(int256 x) internal pure returns (int256 r) { unchecked { // When the result is less than 0.5 we return zero. // This happens when `x <= floor(log(0.5e18) * 1e18) ≈ -42e18`. if (x <= -41446531673892822313) return r; /// @solidity memory-safe-assembly assembly { // When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as // an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`. if iszero(slt(x, 135305999368893231589)) { mstore(0x00, 0xa37bfec9) // `ExpOverflow()`. revert(0x1c, 0x04) } } // `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96` // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5 ** 18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96; x = x - k * 54916777467707473351141471128; // `k` is in the range `[-61, 195]`. // Evaluate using a (6, 7)-term rational approximation. // `p` is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already `2**96` too large. r := sdiv(p, q) } // r should be in the range `(0.09, 0.25) * 2**96`. // We now need to multiply r by: // - The scale factor `s ≈ 6.031367120`. // - The `2**k` factor from the range reduction. // - The `1e18 / 2**96` factor for base conversion. // We do this all at once, with an intermediate result in `2**213` // basis, so the final right shift is always by a positive amount. r = int256( (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k) ); } } /// @dev Returns `ln(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/21/exp-ln function lnWad(int256 x) internal pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // We want to convert `x` from `10**18` fixed point to `2**96` fixed point. // We do this by multiplying by `2**96 / 10**18`. But since // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here // and add `ln(2**96 / 10**18)` at the end. // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`. r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, 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)))) // We place the check here for more optimal stack operations. if iszero(sgt(x, 0)) { mstore(0x00, 0x1615e638) // `LnWadUndefined()`. revert(0x1c, 0x04) } // forgefmt: disable-next-item r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)) // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) x := shr(159, shl(r, x)) // Evaluate using a (8, 8)-term rational approximation. // `p` is made monic, we will multiply by a scale factor later. // forgefmt: disable-next-item let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir. sar(96, mul(add(43456485725739037958740375743393, sar(96, mul(add(24828157081833163892658089445524, sar(96, mul(add(3273285459638523848632254066296, x), x))), x))), x)), 11111509109440967052023855526967) p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857) p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526) p := sub(mul(p, x), shl(96, 795164235651350426258249787498)) // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. // `q` is monic by convention. let q := add(5573035233440673466300451813936, x) q := add(71694874799317883764090561454958, sar(96, mul(x, q))) q := add(283447036172924575727196451306956, sar(96, mul(x, q))) q := add(401686690394027663651624208769553, sar(96, mul(x, q))) q := add(204048457590392012362485061816622, sar(96, mul(x, q))) q := add(31853899698501571402653359427138, sar(96, mul(x, q))) q := add(909429971244387300277376558375, sar(96, mul(x, q))) // `p / q` is in the range `(0, 0.125) * 2**96`. // Finalization, we need to: // - Multiply by the scale factor `s = 5.549…`. // - Add `ln(2**96 / 10**18)`. // - Add `k * ln(2)`. // - Multiply by `10**18 / 2**96 = 5**18 >> 78`. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already `2**96` too large. p := sdiv(p, q) // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`. p := mul(1677202110996718588342820967067443963516166, p) // Add `ln(2) * k * 5**18 * 2**192`. // forgefmt: disable-next-item p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p) // Add `ln(2**96 / 10**18) * 5**18 * 2**192`. p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p) // Base conversion: mul `2**18 / 2**192`. r := sar(174, p) } } /// @dev Returns `W_0(x)`, denominated in `WAD`. /// See: https://en.wikipedia.org/wiki/Lambert_W_function /// a.k.a. Product log function. This is an approximation of the principal branch. function lambertW0Wad(int256 x) internal pure returns (int256 w) { // forgefmt: disable-next-item unchecked { if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`. int256 wad = int256(WAD); int256 p = x; uint256 c; // Whether we need to avoid catastrophic cancellation. uint256 i = 4; // Number of iterations. if (w <= 0x1ffffffffffff) { if (-0x4000000000000 <= w) { i = 1; // Inputs near zero only take one step to converge. } else if (w <= -0x3ffffffffffffff) { i = 32; // Inputs near `-1/e` take very long to converge. } } else if (w >> 63 == 0) { /// @solidity memory-safe-assembly assembly { // Inline log2 for more performance, since the range is small. let v := shr(49, w) let l := shl(3, lt(0xff, v)) l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)), 49) w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13)) c := gt(l, 60) i := add(2, add(gt(l, 53), c)) } } else { int256 ll = lnWad(w = lnWad(w)); /// @solidity memory-safe-assembly assembly { // `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`. w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll)) i := add(3, iszero(shr(68, x))) c := iszero(shr(143, x)) } if (c == 0) { do { // If `x` is big, use Newton's so that intermediate values won't overflow. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := mul(w, div(e, wad)) w := sub(w, sdiv(sub(t, x), div(add(e, t), wad))) } if (p <= w) break; p = w; } while (--i != 0); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } return w; } } do { // Otherwise, use Halley's for faster convergence. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := add(w, wad) let s := sub(mul(w, e), mul(x, wad)) w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t))))) } if (p <= w) break; p = w; } while (--i != c); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } // For certain ranges of `x`, we'll use the quadratic-rate recursive formula of // R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation. if (c != 0) { int256 t = w | 1; /// @solidity memory-safe-assembly assembly { x := sdiv(mul(x, wad), t) } x = (t * (wad + lnWad(x))); /// @solidity memory-safe-assembly assembly { w := sdiv(x, add(wad, t)) } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GENERAL NUMBER UTILITIES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Calculates `floor(a * b / d)` with full precision. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { // 512-bit multiply `[p1 p0] = x * y`. // Compute the product mod `2**256` and mod `2**256 - 1` // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that `product = p1 * 2**256 + p0`. // Least significant 256 bits of the product. result := mul(x, y) // Temporarily use `result` as `p0` to save gas. let mm := mulmod(x, y, not(0)) // Most significant 256 bits of the product. let p1 := sub(mm, add(result, lt(mm, result))) // Handle non-overflow cases, 256 by 256 division. if iszero(p1) { if iszero(d) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } result := div(result, d) break } // Make sure the result is less than `2**256`. Also prevents `d == 0`. if iszero(gt(d, p1)) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } /*------------------- 512 by 256 division --------------------*/ // Make division exact by subtracting the remainder from `[p1 p0]`. // Compute remainder using mulmod. let r := mulmod(x, y, d) // `t` is the least significant bit of `d`. // Always greater or equal to 1. let t := and(d, sub(0, d)) // Divide `d` by `t`, which is a power of two. d := div(d, t) // Invert `d mod 2**256` // Now that `d` is an odd number, it has an inverse // modulo `2**256` such that `d * inv = 1 mod 2**256`. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, `d * inv = 1 mod 2**4`. let inv := xor(2, mul(3, d)) // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128 result := mul( // Divide [p1 p0] by the factors of two. // Shift in bits from `p1` into `p0`. For this we need // to flip `t` such that it is `2**256 / t`. or( mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)), div(sub(result, r), t) ), // inverse mod 2**256 mul(inv, sub(2, mul(d, inv))) ) break } } } /// @dev Calculates `floor(x * y / d)` with full precision, rounded up. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Uniswap-v3-core under MIT license: /// https://github.com/Uniswap/v3-core/blob/contracts/libraries/FullMath.sol function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) { result = fullMulDiv(x, y, d); /// @solidity memory-safe-assembly assembly { if mulmod(x, y, d) { result := add(result, 1) if iszero(result) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } } } } /// @dev Returns `floor(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := div(mul(x, y), d) } } /// @dev Returns `ceil(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d)) } } /// @dev Returns `ceil(x / d)`. /// Reverts if `d` is zero. function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { if iszero(d) { mstore(0x00, 0x65244e4e) // `DivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(x, d))), div(x, d)) } } /// @dev Returns `max(0, x - y)`. function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(gt(x, y), sub(x, y)) } } /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`. /// Reverts if the computation overflows. function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`. if x { z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x` let half := shr(1, b) // Divide `b` by 2. // Divide `y` by 2 every iteration. for { y := shr(1, y) } y { y := shr(1, y) } { let xx := mul(x, x) // Store x squared. let xxRound := add(xx, half) // Round to the nearest number. // Revert if `xx + half` overflowed, or if `x ** 2` overflows. if or(lt(xxRound, xx), shr(128, x)) { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } x := div(xxRound, b) // Set `x` to scaled `xxRound`. // If `y` is odd: if and(y, 1) { let zx := mul(z, x) // Compute `z * x`. let zxRound := add(zx, half) // Round to the nearest number. // If `z * x` overflowed or `zx + half` overflowed: if or(xor(div(zx, x), z), lt(zxRound, zx)) { // Revert if `x` is non-zero. if iszero(iszero(x)) { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } } z := div(zxRound, b) // Return properly scaled `zxRound`. } } } } } /// @dev Returns the square root of `x`. function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // Let `y = x / 2**r`. We check `y >= 2**(k + 8)` // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`. let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffffff, shr(r, x)))) z := shl(shr(1, r), z) // Goal was to get `z*z*y` within a small factor of `x`. More iterations could // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`. // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small. // That's not possible if `x < 256` but we can just verify those cases exhaustively. // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`. // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`. // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps. // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)` // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`, // with largest error when `s = 1` and when `s = 256` or `1/256`. // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`. // Then we can estimate `sqrt(y)` using // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`. // There is no overflow risk here since `y < 2**136` after the first branch above. z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If `x+1` is a perfect square, the Babylonian method cycles between // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division z := sub(z, lt(div(x, z), z)) } } /// @dev Returns the cube root of `x`. /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license: /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy function cbrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, 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)))) z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3))) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := sub(z, lt(div(x, mul(z, z)), z)) } } /// @dev Returns the square root of `x`, denominated in `WAD`. function sqrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { z = 10 ** 9; if (x <= type(uint256).max / 10 ** 36 - 1) { x *= 10 ** 18; z = 1; } z *= sqrt(x); } } /// @dev Returns the cube root of `x`, denominated in `WAD`. function cbrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { z = 10 ** 12; if (x <= (type(uint256).max / 10 ** 36) * 10 ** 18 - 1) { if (x >= type(uint256).max / 10 ** 36) { x *= 10 ** 18; z = 10 ** 6; } else { x *= 10 ** 36; z = 1; } } z *= cbrt(x); } } /// @dev Returns the factorial of `x`. function factorial(uint256 x) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if iszero(lt(x, 58)) { mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`. revert(0x1c, 0x04) } for { result := 1 } x { x := sub(x, 1) } { result := mul(result, x) } } } /// @dev Returns the log2 of `x`. /// Equivalent to computing the index of the most significant bit (MSB) of `x`. /// Returns 0 if `x` is zero. function log2(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, 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 r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)) } } /// @dev Returns the log2 of `x`, rounded up. /// Returns 0 if `x` is zero. function log2Up(uint256 x) internal pure returns (uint256 r) { r = log2(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(r, 1), x)) } } /// @dev Returns the log10 of `x`. /// Returns 0 if `x` is zero. function log10(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { if iszero(lt(x, 100000000000000000000000000000000000000)) { x := div(x, 100000000000000000000000000000000000000) r := 38 } if iszero(lt(x, 100000000000000000000)) { x := div(x, 100000000000000000000) r := add(r, 20) } if iszero(lt(x, 10000000000)) { x := div(x, 10000000000) r := add(r, 10) } if iszero(lt(x, 100000)) { x := div(x, 100000) r := add(r, 5) } r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999))))) } } /// @dev Returns the log10 of `x`, rounded up. /// Returns 0 if `x` is zero. function log10Up(uint256 x) internal pure returns (uint256 r) { r = log10(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(exp(10, r), x)) } } /// @dev Returns the log256 of `x`. /// Returns 0 if `x` is zero. function log256(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, 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(shr(3, r), lt(0xff, shr(r, x))) } } /// @dev Returns the log256 of `x`, rounded up. /// Returns 0 if `x` is zero. function log256Up(uint256 x) internal pure returns (uint256 r) { r = log256(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(shl(3, r), 1), x)) } } /// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`. /// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent). function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) { /// @solidity memory-safe-assembly assembly { mantissa := x if mantissa { if iszero(mod(mantissa, 1000000000000000000000000000000000)) { mantissa := div(mantissa, 1000000000000000000000000000000000) exponent := 33 } if iszero(mod(mantissa, 10000000000000000000)) { mantissa := div(mantissa, 10000000000000000000) exponent := add(exponent, 19) } if iszero(mod(mantissa, 1000000000000)) { mantissa := div(mantissa, 1000000000000) exponent := add(exponent, 12) } if iszero(mod(mantissa, 1000000)) { mantissa := div(mantissa, 1000000) exponent := add(exponent, 6) } if iszero(mod(mantissa, 10000)) { mantissa := div(mantissa, 10000) exponent := add(exponent, 4) } if iszero(mod(mantissa, 100)) { mantissa := div(mantissa, 100) exponent := add(exponent, 2) } if iszero(mod(mantissa, 10)) { mantissa := div(mantissa, 10) exponent := add(exponent, 1) } } } } /// @dev Convenience function for packing `x` into a smaller number using `sci`. /// The `mantissa` will be in bits [7..255] (the upper 249 bits). /// The `exponent` will be in bits [0..6] (the lower 7 bits). /// Use `SafeCastLib` to safely ensure that the `packed` number is small /// enough to fit in the desired unsigned integer type: /// ``` /// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether)); /// ``` function packSci(uint256 x) internal pure returns (uint256 packed) { (x, packed) = sci(x); // Reuse for `mantissa` and `exponent`. /// @solidity memory-safe-assembly assembly { if shr(249, x) { mstore(0x00, 0xce30380c) // `MantissaOverflow()`. revert(0x1c, 0x04) } packed := or(shl(7, x), packed) } } /// @dev Convenience function for unpacking a packed number from `packSci`. function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) { unchecked { unpacked = (packed >> 7) * 10 ** (packed & 0x7f); } } /// @dev Returns the average of `x` and `y`. function avg(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = (x & y) + ((x ^ y) >> 1); } } /// @dev Returns the average of `x` and `y`. function avg(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = (x >> 1) + (y >> 1) + (((x & 1) + (y & 1)) >> 1); } } /// @dev Returns the absolute value of `x`. function abs(int256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(sub(0, shr(255, x)), add(sub(0, shr(255, x)), x)) } } /// @dev Returns the absolute distance between `x` and `y`. function dist(int256 x, int256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(mul(xor(sub(y, x), sub(x, y)), sgt(x, y)), sub(y, x)) } } /// @dev Returns the minimum of `x` and `y`. function min(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), lt(y, x))) } } /// @dev Returns the minimum of `x` and `y`. function min(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), slt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), gt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), sgt(y, x))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(uint256 x, uint256 minValue, uint256 maxValue) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), gt(minValue, x))) z := xor(z, mul(xor(z, maxValue), lt(maxValue, z))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), sgt(minValue, x))) z := xor(z, mul(xor(z, maxValue), slt(maxValue, z))) } } /// @dev Returns greatest common divisor of `x` and `y`. function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { for { z := x } y {} { let t := y y := mod(z, y) z := t } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RAW NUMBER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `x + y`, without checking for overflow. function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x + y; } } /// @dev Returns `x + y`, without checking for overflow. function rawAdd(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x + y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x - y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x - y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x * y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x * y; } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(x, y) } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mod(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawSMod(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := smod(x, y) } } /// @dev Returns `(x + y) % d`, return 0 if `d` if zero. function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := addmod(x, y, d) } } /// @dev Returns `(x * y) % d`, return 0 if `d` if zero. function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mulmod(x, y, d) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// /// @dev Note: /// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection. /// - For ERC20s, this implementation won't check that a token has code, /// responsibility is delegated to the caller. library SafeTransferLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ETH transfer has failed. error ETHTransferFailed(); /// @dev The ERC20 `transferFrom` has failed. error TransferFromFailed(); /// @dev The ERC20 `transfer` has failed. error TransferFailed(); /// @dev The ERC20 `approve` has failed. error ApproveFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes. uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300; /// @dev Suggested gas stipend for contract receiving ETH to perform a few /// storage reads and writes, but low enough to prevent griefing. uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ETH OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants. // // The regular variants: // - Forwards all remaining gas to the target. // - Reverts if the target reverts. // - Reverts if the current contract has insufficient balance. // // The force variants: // - Forwards with an optional gas stipend // (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases). // - If the target reverts, or if the gas stipend is exhausted, // creates a temporary contract to force send the ETH via `SELFDESTRUCT`. // Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758. // - Reverts if the current contract has insufficient balance. // // The try variants: // - Forwards with a mandatory gas stipend. // - Instead of reverting, returns whether the transfer succeeded. /// @dev Sends `amount` (in wei) ETH to `to`. function safeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } } } /// @dev Sends all the ETH in the current contract to `to`. function safeTransferAllETH(address to) internal { /// @solidity memory-safe-assembly assembly { // Transfer all the ETH and check if it succeeded or not. if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`. function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { if lt(selfbalance(), amount) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`. function forceSafeTransferAllETH(address to, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`. function forceSafeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { if lt(selfbalance(), amount) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`. function forceSafeTransferAllETH(address to) internal { /// @solidity memory-safe-assembly assembly { // forgefmt: disable-next-item if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`. function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00) } } /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`. function trySafeTransferAllETH(address to, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferFrom(address token, address from, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, amount) // Store the `amount` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends all of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have their entire balance approved for /// the current contract to manage. function safeTransferAllFrom(address token, address from, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`. // Read the balance, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`. amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransfer(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sends all of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransferAll(address token, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, address()) // Store the address of the current contract. // Read the balance, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x14, to) // Store the `to` argument. amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// Reverts upon failure. function safeApprove(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. // Perform the approval, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// If the initial attempt to approve fails, attempts to reset the approved amount to zero, /// then retries the approval again (some tokens, e.g. USDT, requires this). /// Reverts upon failure. function safeApproveWithRetry(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. // Perform the approval, retrying upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x34, 0) // Store 0 for the `amount`. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval. mstore(0x34, amount) // Store back the original `amount`. // Retry the approval, reverting upon failure. if iszero( and( or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`. revert(0x1c, 0x04) } } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Returns the amount of ERC20 `token` owned by `account`. /// Returns zero if the `token` does not exist. function balanceOf(address token, address account) internal view returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x14, account) // Store the `account` argument. mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`. amount := mul( mload(0x20), and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20) ) ) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Signature verification helper that supports both ECDSA signatures from EOAs /// and ERC1271 signatures from smart contract wallets like Argent and Gnosis safe. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SignatureCheckerLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol) /// /// @dev Note: /// - The signature checking functions use the ecrecover precompile (0x1). /// - The `bytes memory signature` variants use the identity precompile (0x4) /// to copy memory internally. /// - Unlike ECDSA signatures, contract signatures are revocable. /// - As of Solady version 0.0.134, all `bytes signature` variants accept both /// regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures. /// See: https://eips.ethereum.org/EIPS/eip-2098 /// This is for calldata efficiency on smart accounts prevalent on L2s. /// /// WARNING! Do NOT use signatures as unique identifiers: /// - Use a nonce in the digest to prevent replay attacks on the same contract. /// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts. /// EIP-712 also enables readable signing of typed data for better user safety. /// This implementation does NOT check if a signature is non-malleable. library SignatureCheckerLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIGNATURE CHECKING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `signature` is valid for `signer` and `hash`. /// If `signer` is a smart contract, the signature is validated with ERC1271. /// Otherwise, the signature is validated with `ECDSA.recover`. function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits of `signer` in case they are dirty. for { signer := shr(96, shl(96, signer)) } signer {} { let m := mload(0x40) mstore(0x00, hash) mstore(0x40, mload(add(signature, 0x20))) // `r`. if eq(mload(signature), 64) { let vs := mload(add(signature, 0x40)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x60, shr(1, shl(1, vs))) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } if eq(mload(signature), 65) { mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x60, mload(add(signature, 0x40))) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. // Copy the `signature` over. let n := add(0x20, mload(signature)) pop(staticcall(gas(), 4, signature, n, add(m, 0x44), n)) // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. add(returndatasize(), 0x44), // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) break } } } /// @dev Returns whether `signature` is valid for `signer` and `hash`. /// If `signer` is a smart contract, the signature is validated with ERC1271. /// Otherwise, the signature is validated with `ECDSA.recover`. function isValidSignatureNowCalldata(address signer, bytes32 hash, bytes calldata signature) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits of `signer` in case they are dirty. for { signer := shr(96, shl(96, signer)) } signer {} { let m := mload(0x40) mstore(0x00, hash) if eq(signature.length, 64) { let vs := calldataload(add(signature.offset, 0x20)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, calldataload(signature.offset)) // `r`. mstore(0x60, shr(1, shl(1, vs))) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } if eq(signature.length, 65) { mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. calldatacopy(0x40, signature.offset, 0x40) // `r`, `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), signature.length) // Copy the `signature` over. calldatacopy(add(m, 0x64), signature.offset, signature.length) // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. add(signature.length, 0x64), // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) break } } } /// @dev Returns whether the signature (`r`, `vs`) is valid for `signer` and `hash`. /// If `signer` is a smart contract, the signature is validated with ERC1271. /// Otherwise, the signature is validated with `ECDSA.recover`. function isValidSignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits of `signer` in case they are dirty. for { signer := shr(96, shl(96, signer)) } signer {} { let m := mload(0x40) mstore(0x00, hash) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, r) // `r`. mstore(0x60, shr(1, shl(1, vs))) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), mload(0x60)) // `s`. mstore8(add(m, 0xa4), mload(0x20)) // `v`. // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. 0xa5, // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } } /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `signer` and `hash`. /// If `signer` is a smart contract, the signature is validated with ERC1271. /// Otherwise, the signature is validated with `ECDSA.recover`. function isValidSignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits of `signer` in case they are dirty. for { signer := shr(96, shl(96, signer)) } signer {} { let m := mload(0x40) mstore(0x00, hash) mstore(0x20, and(v, 0xff)) // `v`. mstore(0x40, r) // `r`. mstore(0x60, s) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), s) // `s`. mstore8(add(m, 0xa4), v) // `v`. // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. 0xa5, // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1271 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract. function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. // Copy the `signature` over. let n := add(0x20, mload(signature)) pop(staticcall(gas(), 4, signature, n, add(m, 0x44), n)) // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. add(returndatasize(), 0x44), // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) } } /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract. function isValidERC1271SignatureNowCalldata( address signer, bytes32 hash, bytes calldata signature ) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), signature.length) // Copy the `signature` over. calldatacopy(add(m, 0x64), signature.offset, signature.length) // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. add(signature.length, 0x64), // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) } } /// @dev Returns whether the signature (`r`, `vs`) is valid for `hash` /// for an ERC1271 `signer` contract. function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`. mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`. // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. 0xa5, // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) } } /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `hash` /// for an ERC1271 `signer` contract. function isValidERC1271SignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), s) // `s`. mstore8(add(m, 0xa4), v) // `v`. // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. 0xa5, // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HASHING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an Ethereum Signed Message, created from a `hash`. /// This produces a hash corresponding to the one signed with the /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) /// JSON-RPC method as part of EIP-191. function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, hash) // Store into scratch space for keccak256. mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes. result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`. } } /// @dev Returns an Ethereum Signed Message, created from `s`. /// This produces a hash corresponding to the one signed with the /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) /// JSON-RPC method as part of EIP-191. /// Note: Supports lengths of `s` up to 999999 bytes. function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let sLength := mload(s) let o := 0x20 mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded. mstore(0x00, 0x00) // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`. for { let temp := sLength } 1 {} { o := sub(o, 1) mstore8(o, add(48, mod(temp, 10))) temp := div(temp, 10) if iszero(temp) { break } } let n := sub(0x3a, o) // Header length: `26 + 32 - o`. // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes. returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20)) mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header. result := keccak256(add(s, sub(0x20, n)), add(n, sLength)) mstore(s, sLength) // Restore the length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EMPTY CALLDATA HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an empty calldata bytes. function emptySignature() internal pure returns (bytes calldata signature) { /// @solidity memory-safe-assembly assembly { signature.length := 0 } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {ReceivedItem, Schema, SpentItem} from "../lib/ConsiderationStructs.sol"; import {IERC165} from "../interfaces/IERC165.sol"; /** * @title ContractOffererInterface * @notice Contains the minimum interfaces needed to interact with a contract * offerer. */ interface ContractOffererInterface is IERC165 { /** * @dev Generates an order with the specified minimum and maximum spent * items, and optional context (supplied as extraData). * * @param fulfiller The address of the fulfiller. * @param minimumReceived The minimum items that the caller is willing to * receive. * @param maximumSpent The maximum items the caller is willing to spend. * @param context Additional context of the order. * * @return offer A tuple containing the offer items. * @return consideration A tuple containing the consideration items. */ function generateOrder( address fulfiller, SpentItem[] calldata minimumReceived, SpentItem[] calldata maximumSpent, bytes calldata context // encoded based on the schemaID ) external returns (SpentItem[] memory offer, ReceivedItem[] memory consideration); /** * @dev Ratifies an order with the specified offer, consideration, and * optional context (supplied as extraData). * * @param offer The offer items. * @param consideration The consideration items. * @param context Additional context of the order. * @param orderHashes The hashes to ratify. * @param contractNonce The nonce of the contract. * * @return ratifyOrderMagicValue The magic value returned by the contract * offerer. */ function ratifyOrder( SpentItem[] calldata offer, ReceivedItem[] calldata consideration, bytes calldata context, // encoded based on the schemaID bytes32[] calldata orderHashes, uint256 contractNonce ) external returns (bytes4 ratifyOrderMagicValue); /** * @dev View function to preview an order generated in response to a minimum * set of received items, maximum set of spent items, and context * (supplied as extraData). * * @param caller The address of the caller (e.g. Seaport). * @param fulfiller The address of the fulfiller (e.g. the account * calling Seaport). * @param minimumReceived The minimum items that the caller is willing to * receive. * @param maximumSpent The maximum items the caller is willing to spend. * @param context Additional context of the order. * * @return offer A tuple containing the offer items. * @return consideration A tuple containing the consideration items. */ function previewOrder( address caller, address fulfiller, SpentItem[] calldata minimumReceived, SpentItem[] calldata maximumSpent, bytes calldata context // encoded based on the schemaID ) external view returns (SpentItem[] memory offer, ReceivedItem[] memory consideration); /** * @dev Gets the metadata for this contract offerer. * * @return name The name of the contract offerer. * @return schemas The schemas supported by the contract offerer. */ function getSeaportMetadata() external view returns (string memory name, Schema[] memory schemas); // map to Seaport Improvement Proposal IDs function supportsInterface(bytes4 interfaceId) external view override returns (bool); // Additional functions and/or events based on implemented schemaIDs }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC721 implementation with storage hitchhiking. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC721.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721/ERC721.sol) /// /// @dev Note: /// - The ERC721 standard allows for self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. /// - For performance, methods are made payable where permitted by the ERC721 standard. /// - The `safeTransfer` functions use the identity precompile (0x4) /// to copy memory internally. /// /// If you are overriding: /// - NEVER violate the ERC721 invariant: /// the balance of an owner MUST always be equal to their number of ownership slots. /// The transfer functions do not have an underflow guard for user token balances. /// - Make sure all variables written to storage are properly cleaned // (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood). /// - Check that the overridden function is actually used in the function you want to /// change the behavior of. Much of the code has been manually inlined for performance. abstract contract ERC721 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev An account can hold up to 4294967295 tokens. uint256 internal constant _MAX_ACCOUNT_BALANCE = 0xffffffff; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Only the token owner or an approved account can manage the token. error NotOwnerNorApproved(); /// @dev The token does not exist. error TokenDoesNotExist(); /// @dev The token already exists. error TokenAlreadyExists(); /// @dev Cannot query the balance for the zero address. error BalanceQueryForZeroAddress(); /// @dev Cannot mint or transfer to the zero address. error TransferToZeroAddress(); /// @dev The token must be owned by `from`. error TransferFromIncorrectOwner(); /// @dev The recipient's balance has overflowed. error AccountBalanceOverflow(); /// @dev Cannot safely transfer to a contract that does not implement /// the ERC721Receiver interface. error TransferToNonERC721ReceiverImplementer(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when token `id` is transferred from `from` to `to`. event Transfer(address indexed from, address indexed to, uint256 indexed id); /// @dev Emitted when `owner` enables `account` to manage the `id` token. event Approval(address indexed owner, address indexed account, uint256 indexed id); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`. uint256 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`. uint256 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership data slot of `id` is given by: /// ``` /// mstore(0x00, id) /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) /// ``` /// Bits Layout: /// - [0..159] `addr` /// - [160..255] `extraData` /// /// The approved address slot is given by: `add(1, ownershipSlot)`. /// /// See: https://notes.ethereum.org/%40vbuterin/verkle_tree_eip /// /// The balance slot of `owner` is given by: /// ``` /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// mstore(0x00, owner) /// let balanceSlot := keccak256(0x0c, 0x1c) /// ``` /// Bits Layout: /// - [0..31] `balance` /// - [32..255] `aux` /// /// The `operator` approval slot of `owner` is given by: /// ``` /// mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) /// mstore(0x00, owner) /// let operatorApprovalSlot := keccak256(0x0c, 0x30) /// ``` uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192; /// @dev Pre-shifted and pre-masked constant. uint256 private constant _ERC721_MASTER_SLOT_SEED_MASKED = 0x0a5a2e7a00000000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the token collection name. function name() public view virtual returns (string memory); /// @dev Returns the token collection symbol. function symbol() public view virtual returns (string memory); /// @dev Returns the Uniform Resource Identifier (URI) for token `id`. function tokenURI(uint256 id) public view virtual returns (string memory); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of token `id`. /// /// Requirements: /// - Token `id` must exist. function ownerOf(uint256 id) public view virtual returns (address result) { result = _ownerOf(id); /// @solidity memory-safe-assembly assembly { if iszero(result) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } } } /// @dev Returns the number of tokens owned by `owner`. /// /// Requirements: /// - `owner` must not be the zero address. function balanceOf(address owner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Revert if the `owner` is the zero address. if iszero(owner) { mstore(0x00, 0x8f4eb604) // `BalanceQueryForZeroAddress()`. revert(0x1c, 0x04) } mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := and(sload(keccak256(0x0c, 0x1c)), _MAX_ACCOUNT_BALANCE) } } /// @dev Returns the account approved to manage token `id`. /// /// Requirements: /// - Token `id` must exist. function getApproved(uint256 id) public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) if iszero(shl(96, sload(ownershipSlot))) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } result := sload(add(1, ownershipSlot)) } } /// @dev Sets `account` as the approved account to manage token `id`. /// /// Requirements: /// - Token `id` must exist. /// - The caller must be the owner of the token, /// or an approved operator for the token owner. /// /// Emits an {Approval} event. function approve(address account, uint256 id) public payable virtual { _approve(msg.sender, account, id); } /// @dev Returns whether `operator` is approved to manage the tokens of `owner`. function isApprovedForAll(address owner, address operator) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x30)) } } /// @dev Sets whether `operator` is approved to manage the tokens of the caller. /// /// Emits an {ApprovalForAll} event. function setApprovalForAll(address operator, bool isApproved) public virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`msg.sender`, `operator`). mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) // forgefmt: disable-next-item log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator))) } } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function transferFrom(address from, address to, uint256 id) public payable virtual { _beforeTokenTransfer(from, to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) from := and(bitmaskAddress, from) to := and(bitmaskAddress, to) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, caller())) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) let owner := and(bitmaskAddress, ownershipPacked) // Revert if `from` is not the owner, or does not exist. if iszero(mul(owner, eq(owner, from))) { if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } mstore(0x00, 0xa1148100) // `TransferFromIncorrectOwner()`. revert(0x1c, 0x04) } // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Load, check, and update the token approval. { mstore(0x00, from) let approvedAddress := sload(add(1, ownershipSlot)) // Revert if the caller is not the owner, nor approved. if iszero(or(eq(caller(), from), eq(caller(), approvedAddress))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Update with the new owner. sstore(ownershipSlot, xor(ownershipPacked, xor(from, to))) // Decrement the balance of `from`. { let fromBalanceSlot := keccak256(0x0c, 0x1c) sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1)) } // Increment the balance of `to`. { mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x1c) let toBalanceSlotPacked := add(sload(toBalanceSlot), 1) if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) } _afterTokenTransfer(from, to, id); } /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`. function safeTransferFrom(address from, address to, uint256 id) public payable virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function safeTransferFrom(address from, address to, uint256 id, bytes calldata data) public payable virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f. result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL QUERY FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns if token `id` exists. function _exists(uint256 id) internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := iszero(iszero(shl(96, sload(add(id, add(id, keccak256(0x00, 0x20))))))) } } /// @dev Returns the owner of token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _ownerOf(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(96, shl(96, sload(add(id, add(id, keccak256(0x00, 0x20)))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL DATA HITCHHIKING FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance, no events are emitted for the hitchhiking setters. // Please emit your own events if required. /// @dev Returns the auxiliary data for `owner`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _getAux(address owner) internal view virtual returns (uint224 result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := shr(32, sload(keccak256(0x0c, 0x1c))) } } /// @dev Set the auxiliary data for `owner` to `value`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _setAux(address owner, uint224 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) let balanceSlot := keccak256(0x0c, 0x1c) let packed := sload(balanceSlot) sstore(balanceSlot, xor(packed, shl(32, xor(value, shr(32, packed))))) } } /// @dev Returns the extra data for token `id`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _getExtraData(uint256 id) internal view virtual returns (uint96 result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(160, sload(add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Sets the extra data for token `id` to `value`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _setExtraData(uint256 id, uint96 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let packed := sload(ownershipSlot) sstore(ownershipSlot, xor(packed, shl(160, xor(value, shr(160, packed))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// /// Emits a {Transfer} event. function _mint(address to, uint256 id) internal virtual { _beforeTokenTransfer(address(0), to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. to := shr(96, shl(96, to)) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Load the ownership data. mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) // Revert if the token already exists. if shl(96, ownershipPacked) { mstore(0x00, 0xc991cbb1) // `TokenAlreadyExists()`. revert(0x1c, 0x04) } // Update with the owner. sstore(ownershipSlot, or(ownershipPacked, to)) // Increment the balance of the owner. { mstore(0x00, to) let balanceSlot := keccak256(0x0c, 0x1c) let balanceSlotPacked := add(sload(balanceSlot), 1) if iszero(and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(balanceSlot, balanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id) } _afterTokenTransfer(address(0), to, id); } /// @dev Equivalent to `_safeMint(to, id, "")`. function _safeMint(address to, uint256 id) internal virtual { _safeMint(to, id, ""); } /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeMint(address to, uint256 id, bytes memory data) internal virtual { _mint(to, id); if (_hasCode(to)) _checkOnERC721Received(address(0), to, id, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_burn(address(0), id)`. function _burn(uint256 id) internal virtual { _burn(address(0), id); } /// @dev Destroys token `id`, using `by`. /// /// Requirements: /// /// - Token `id` must exist. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _burn(address by, uint256 id) internal virtual { address owner = ownerOf(id); _beforeTokenTransfer(owner, address(0), id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. by := shr(96, shl(96, by)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) // Reload the owner in case it is changed in `_beforeTokenTransfer`. owner := shr(96, shl(96, ownershipPacked)) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // Load and check the token approval. { mstore(0x00, owner) let approvedAddress := sload(add(1, ownershipSlot)) // If `by` is not the zero address, do the authorization check. // Revert if the `by` is not the owner, nor approved. if iszero(or(iszero(by), or(eq(by, owner), eq(by, approvedAddress)))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Clear the owner. sstore(ownershipSlot, xor(ownershipPacked, owner)) // Decrement the balance of `owner`. { let balanceSlot := keccak256(0x0c, 0x1c) sstore(balanceSlot, sub(sload(balanceSlot), 1)) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, owner, 0, id) } _afterTokenTransfer(owner, address(0), id); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL APPROVAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `account` is the owner of token `id`, or is approved to manage it. /// /// Requirements: /// - Token `id` must exist. function _isApprovedOrOwner(address account, uint256 id) internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 // Clear the upper 96 bits. account := shr(96, shl(96, account)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, account)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let owner := shr(96, shl(96, sload(ownershipSlot))) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // Check if `account` is the `owner`. if iszero(eq(account, owner)) { mstore(0x00, owner) // Check if `account` is approved to manage the token. if iszero(sload(keccak256(0x0c, 0x30))) { result := eq(account, sload(add(1, ownershipSlot))) } } } } /// @dev Returns the account approved to manage token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _getApproved(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := sload(add(1, add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Equivalent to `_approve(address(0), account, id)`. function _approve(address account, uint256 id) internal virtual { _approve(address(0), account, id); } /// @dev Sets `account` as the approved account to manage token `id`, using `by`. /// /// Requirements: /// - Token `id` must exist. /// - If `by` is not the zero address, `by` must be the owner /// or an approved operator for the token owner. /// /// Emits a {Transfer} event. function _approve(address by, address account, uint256 id) internal virtual { assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) account := and(bitmaskAddress, account) by := and(bitmaskAddress, by) // Load the owner of the token. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let owner := and(bitmaskAddress, sload(ownershipSlot)) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // If `by` is not the zero address, do the authorization check. // Revert if `by` is not the owner, nor approved. if iszero(or(iszero(by), eq(by, owner))) { mstore(0x00, owner) if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Sets `account` as the approved account to manage `id`. sstore(add(1, ownershipSlot), account) // Emit the {Approval} event. log4(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id) } } /// @dev Approve or remove the `operator` as an operator for `by`, /// without authorization checks. /// /// Emits an {ApprovalForAll} event. function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual { /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. by := shr(96, shl(96, by)) operator := shr(96, shl(96, operator)) // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`by`, `operator`). mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) mstore(0x00, by) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, by, operator) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_transfer(address(0), from, to, id)`. function _transfer(address from, address to, uint256 id) internal virtual { _transfer(address(0), from, to, id); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _transfer(address by, address from, address to, uint256 id) internal virtual { _beforeTokenTransfer(from, to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) from := and(bitmaskAddress, from) to := and(bitmaskAddress, to) by := and(bitmaskAddress, by) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) let owner := and(bitmaskAddress, ownershipPacked) // Revert if `from` is not the owner, or does not exist. if iszero(mul(owner, eq(owner, from))) { if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } mstore(0x00, 0xa1148100) // `TransferFromIncorrectOwner()`. revert(0x1c, 0x04) } // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Load, check, and update the token approval. { mstore(0x00, from) let approvedAddress := sload(add(1, ownershipSlot)) // If `by` is not the zero address, do the authorization check. // Revert if the `by` is not the owner, nor approved. if iszero(or(iszero(by), or(eq(by, from), eq(by, approvedAddress)))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Update with the new owner. sstore(ownershipSlot, xor(ownershipPacked, xor(from, to))) // Decrement the balance of `from`. { let fromBalanceSlot := keccak256(0x0c, 0x1c) sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1)) } // Increment the balance of `to`. { mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x1c) let toBalanceSlotPacked := add(sload(toBalanceSlot), 1) if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) } _afterTokenTransfer(from, to, id); } /// @dev Equivalent to `_safeTransfer(from, to, id, "")`. function _safeTransfer(address from, address to, uint256 id) internal virtual { _safeTransfer(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeTransfer(address from, address to, uint256 id, bytes memory data) internal virtual { _transfer(address(0), from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /// @dev Equivalent to `_safeTransfer(by, from, to, id, "")`. function _safeTransfer(address by, address from, address to, uint256 id) internal virtual { _safeTransfer(by, from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeTransfer(address by, address from, address to, uint256 id, bytes memory data) internal virtual { _transfer(by, from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS FOR OVERRIDING */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Hook that is called before any token transfers, including minting and burning. function _beforeTokenTransfer(address from, address to, uint256 id) internal virtual {} /// @dev Hook that is called after any token transfers, including minting and burning. function _afterTokenTransfer(address from, address to, uint256 id) internal virtual {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) let onERC721ReceivedSelector := 0x150b7a02 mstore(m, onERC721ReceivedSelector) mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`. mstore(add(m, 0x40), shr(96, shl(96, from))) mstore(add(m, 0x60), id) mstore(add(m, 0x80), 0x80) let n := mload(data) mstore(add(m, 0xa0), n) if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) } // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it. if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) { mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`. revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC1155 implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC1155.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC1155/ERC1155.sol) /// /// @dev Note: /// - The ERC1155 standard allows for self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. /// - The transfer functions use the identity precompile (0x4) /// to copy memory internally. /// /// If you are overriding: /// - Make sure all variables written to storage are properly cleaned // (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood). /// - Check that the overridden function is actually used in the function you want to /// change the behavior of. Much of the code has been manually inlined for performance. abstract contract ERC1155 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The lengths of the input arrays are not the same. error ArrayLengthsMismatch(); /// @dev Cannot mint or transfer to the zero address. error TransferToZeroAddress(); /// @dev The recipient's balance has overflowed. error AccountBalanceOverflow(); /// @dev Insufficient balance. error InsufficientBalance(); /// @dev Only the token owner or an approved account can manage the tokens. error NotOwnerNorApproved(); /// @dev Cannot safely transfer to a contract that does not implement /// the ERC1155Receiver interface. error TransferToNonERC1155ReceiverImplementer(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when `amount` of token `id` is transferred /// from `from` to `to` by `operator`. event TransferSingle( address indexed operator, address indexed from, address indexed to, uint256 id, uint256 amount ); /// @dev Emitted when `amounts` of token `ids` are transferred /// from `from` to `to` by `operator`. event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] amounts ); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev Emitted when the Uniform Resource Identifier (URI) for token `id` /// is updated to `value`. This event is not used in the base contract. /// You may need to emit this event depending on your URI logic. /// /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata event URI(string value, uint256 indexed id); /// @dev `keccak256(bytes("TransferSingle(address,address,address,uint256,uint256)"))`. uint256 private constant _TRANSFER_SINGLE_EVENT_SIGNATURE = 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62; /// @dev `keccak256(bytes("TransferBatch(address,address,address,uint256[],uint256[])"))`. uint256 private constant _TRANSFER_BATCH_EVENT_SIGNATURE = 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `ownerSlotSeed` of a given owner is given by. /// ``` /// let ownerSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner)) /// ``` /// /// The balance slot of `owner` is given by. /// ``` /// mstore(0x20, ownerSlotSeed) /// mstore(0x00, id) /// let balanceSlot := keccak256(0x00, 0x40) /// ``` /// /// The operator approval slot of `owner` is given by. /// ``` /// mstore(0x20, ownerSlotSeed) /// mstore(0x00, operator) /// let operatorApprovalSlot := keccak256(0x0c, 0x34) /// ``` uint256 private constant _ERC1155_MASTER_SLOT_SEED = 0x9a31110384e0b0c9; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1155 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the URI for token `id`. /// /// You can either return the same templated URI for all token IDs, /// (e.g. "https://example.com/api/{id}.json"), /// or return a unique URI for each `id`. /// /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata function uri(uint256 id) public view virtual returns (string memory); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1155 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the amount of `id` owned by `owner`. function balanceOf(address owner, uint256 id) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, owner) mstore(0x00, id) result := sload(keccak256(0x00, 0x40)) } } /// @dev Returns whether `operator` is approved to manage the tokens of `owner`. function isApprovedForAll(address owner, address operator) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, owner) mstore(0x00, operator) result := sload(keccak256(0x0c, 0x34)) } } /// @dev Sets whether `operator` is approved to manage the tokens of the caller. /// /// Emits a {ApprovalForAll} event. function setApprovalForAll(address operator, bool isApproved) public virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`msg.sender`, `operator`). mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, caller()) mstore(0x00, operator) sstore(keccak256(0x0c, 0x34), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) // forgefmt: disable-next-line log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator))) } } /// @dev Transfers `amount` of `id` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - If the caller is not `from`, /// it must be approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer. /// /// Emits a {Transfer} event. function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) public virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from)) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to)) mstore(0x20, fromSlotSeed) // Clear the upper 96 bits. from := shr(96, fromSlotSeed) to := shr(96, toSlotSeed) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // If the caller is not `from`, do the authorization check. if iszero(eq(caller(), from)) { mstore(0x00, caller()) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Subtract and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), from, to) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { // Do the {onERC1155Received} check if `to` is a smart contract. if extcodesize(to) { // Prepare the calldata. let m := mload(0x40) // `onERC1155Received(address,address,uint256,uint256,bytes)`. mstore(m, 0xf23a6e61) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), from) mstore(add(m, 0x60), id) mstore(add(m, 0x80), amount) mstore(add(m, 0xa0), 0xa0) calldatacopy(add(m, 0xc0), sub(data.offset, 0x20), add(0x20, data.length)) // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, data.length), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xf23a6e61))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } } /// @dev Transfers `amounts` of `ids` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - `ids` and `amounts` must have the same length. /// - If the caller is not `from`, /// it must be approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) public virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(ids.length, amounts.length)) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from)) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to)) mstore(0x20, fromSlotSeed) // Clear the upper 96 bits. from := shr(96, fromSlotSeed) to := shr(96, toSlotSeed) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // If the caller is not `from`, do the authorization check. if iszero(eq(caller(), from)) { mstore(0x00, caller()) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { for { let i := shl(5, ids.length) } i {} { i := sub(i, 0x20) let amount := calldataload(add(amounts.offset, i)) // Subtract and store the updated balance of `from`. { mstore(0x20, fromSlotSeed) mstore(0x00, calldataload(add(ids.offset, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, ids.length)) let o := add(m, 0x40) calldatacopy(o, sub(ids.offset, 0x20), n) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, n)) calldatacopy(add(o, n), sub(amounts.offset, 0x20), n) // Do the emit. log4(m, add(add(n, n), 0x40), _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), from, to) } } if (_useAfterTokenTransfer()) { _afterTokenTransferCalldata(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { // Do the {onERC1155BatchReceived} check if `to` is a smart contract. if extcodesize(to) { mstore(0x00, to) // Cache `to` to prevent stack too deep. let m := mload(0x40) // Prepare the calldata. // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`. mstore(m, 0xbc197c81) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), from) // Copy the `ids`. mstore(add(m, 0x60), 0xa0) let n := add(0x20, shl(5, ids.length)) let o := add(m, 0xc0) calldatacopy(o, sub(ids.offset, 0x20), n) // Copy the `amounts`. let s := add(0xa0, n) mstore(add(m, 0x80), s) calldatacopy(add(o, n), sub(amounts.offset, 0x20), n) // Copy the `data`. mstore(add(m, 0xa0), add(s, n)) calldatacopy(add(o, add(n, n)), sub(data.offset, 0x20), add(0x20, data.length)) let nAll := add(0xc4, add(data.length, add(n, n))) // Revert if the call reverts. if iszero(call(gas(), mload(0x00), 0, add(m, 0x1c), nAll, m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xbc197c81))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } } /// @dev Returns the amounts of `ids` for `owners. /// /// Requirements: /// - `owners` and `ids` must have the same length. function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) public view virtual returns (uint256[] memory balances) { /// @solidity memory-safe-assembly assembly { if iszero(eq(ids.length, owners.length)) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } balances := mload(0x40) mstore(balances, ids.length) let o := add(balances, 0x20) let i := shl(5, ids.length) mstore(0x40, add(i, o)) // Loop through all the `ids` and load the balances. for {} i {} { i := sub(i, 0x20) let owner := calldataload(add(owners.offset, i)) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner))) mstore(0x00, calldataload(add(ids.offset, i))) mstore(add(o, i), sload(keccak256(0x00, 0x40))) } } } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC1155: 0xd9b67a26, ERC1155MetadataURI: 0x0e89341c. result := or(or(eq(s, 0x01ffc9a7), eq(s, 0xd9b67a26)), eq(s, 0x0e89341c)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints `amount` of `id` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer. /// /// Emits a {Transfer} event. function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(address(0), to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Increase and store the updated balance of `to`. { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, to) mstore(0x00, id) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), 0, shr(96, to_)) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(address(0), to, _single(id), _single(amount), data); } if (_hasCode(to)) _checkOnERC1155Received(address(0), to, id, amount, data); } /// @dev Mints `amounts` of `ids` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `ids` and `amounts` must have the same length. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function _batchMint( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(address(0), to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Loop through all the `ids` and update the balances. { mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_)) for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } { let amount := mload(add(amounts, i)) // Increase and store the updated balance of `to`. { mstore(0x00, mload(add(ids, i))) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), 0, shr(96, to_)) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(address(0), to, ids, amounts, data); } if (_hasCode(to)) _checkOnERC1155BatchReceived(address(0), to, ids, amounts, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_burn(address(0), from, id, amount)`. function _burn(address from, uint256 id, uint256 amount) internal virtual { _burn(address(0), from, id, amount); } /// @dev Destroys `amount` of `id` from `from`. /// /// Requirements: /// - `from` must have at least `amount` of `id`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// /// Emits a {Transfer} event. function _burn(address by, address from, uint256 id, uint256 amount) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, address(0), _single(id), _single(amount), ""); } /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. if iszero(or(iszero(shl(96, by)), eq(shl(96, by), from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Decrease and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Emit a {TransferSingle} event. mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), 0) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, address(0), _single(id), _single(amount), ""); } } /// @dev Equivalent to `_batchBurn(address(0), from, ids, amounts)`. function _batchBurn(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { _batchBurn(address(0), from, ids, amounts); } /// @dev Destroys `amounts` of `ids` from `from`. /// /// Requirements: /// - `ids` and `amounts` must have the same length. /// - `from` must have at least `amounts` of `ids`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// /// Emits a {TransferBatch} event. function _batchBurn(address by, address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, address(0), ids, amounts, ""); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let from_ := shl(96, from) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } { let amount := mload(add(amounts, i)) // Decrease and store the updated balance of `from`. { mstore(0x00, mload(add(ids, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), 0) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, address(0), ids, amounts, ""); } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL APPROVAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Approve or remove the `operator` as an operator for `by`, /// without authorization checks. /// /// Emits a {ApprovalForAll} event. function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`by`, `operator`). mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, by) mstore(0x00, operator) sstore(keccak256(0x0c, 0x34), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) let m := shr(96, not(0)) log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, and(m, by), and(m, operator)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_safeTransfer(address(0), from, to, id, amount, data)`. function _safeTransfer(address from, address to, uint256 id, uint256 amount, bytes memory data) internal virtual { _safeTransfer(address(0), from, to, id, amount, data); } /// @dev Transfers `amount` of `id` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer. /// /// Emits a {Transfer} event. function _safeTransfer( address by, address from, address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Subtract and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_)) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x20, amount) // forgefmt: disable-next-line log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_)) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, _single(id), _single(amount), data); } if (_hasCode(to)) _checkOnERC1155Received(from, to, id, amount, data); } /// @dev Equivalent to `_safeBatchTransfer(address(0), from, to, ids, amounts, data)`. function _safeBatchTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { _safeBatchTransfer(address(0), from, to, ids, amounts, data); } /// @dev Transfers `amounts` of `ids` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `ids` and `amounts` must have the same length. /// - `from` must have at least `amounts` of `ids`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function _safeBatchTransfer( address by, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let from_ := shl(96, from) let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, from_) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, to_) mstore(0x20, fromSlotSeed) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } { let amount := mload(add(amounts, i)) // Subtract and store the updated balance of `from`. { mstore(0x20, fromSlotSeed) mstore(0x00, mload(add(ids, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_)) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, ids, amounts, data); } if (_hasCode(to)) _checkOnERC1155BatchReceived(from, to, ids, amounts, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS FOR OVERRIDING */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override this function to return true if `_beforeTokenTransfer` is used. /// This is to help the compiler avoid producing dead bytecode. function _useBeforeTokenTransfer() internal view virtual returns (bool) { return false; } /// @dev Hook that is called before any token transfer. /// This includes minting and burning, as well as batched variants. /// /// The same hook is called on both single and batched variants. /// For single transfers, the length of the `id` and `amount` arrays are 1. function _beforeTokenTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} /// @dev Override this function to return true if `_afterTokenTransfer` is used. /// This is to help the compiler avoid producing dead bytecode. function _useAfterTokenTransfer() internal view virtual returns (bool) { return false; } /// @dev Hook that is called after any token transfer. /// This includes minting and burning, as well as batched variants. /// /// The same hook is called on both single and batched variants. /// For single transfers, the length of the `id` and `amount` arrays are 1. function _afterTokenTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Helper for calling the `_afterTokenTransfer` hook. /// This is to help the compiler avoid producing dead bytecode. function _afterTokenTransferCalldata( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) private { if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, ids, amounts, data); } } /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Perform a call to invoke {IERC1155Receiver-onERC1155Received} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC1155Received( address from, address to, uint256 id, uint256 amount, bytes memory data ) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) // `onERC1155Received(address,address,uint256,uint256,bytes)`. mstore(m, 0xf23a6e61) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), shr(96, shl(96, from))) mstore(add(m, 0x60), id) mstore(add(m, 0x80), amount) mstore(add(m, 0xa0), 0xa0) let n := mload(data) mstore(add(m, 0xc0), n) if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xe0), n)) } // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, n), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xf23a6e61))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } /// @dev Perform a call to invoke {IERC1155Receiver-onERC1155BatchReceived} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC1155BatchReceived( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`. mstore(m, 0xbc197c81) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), shr(96, shl(96, from))) // Copy the `ids`. mstore(add(m, 0x60), 0xa0) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0xc0) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. let s := add(0xa0, returndatasize()) mstore(add(m, 0x80), s) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) // Copy the `data`. mstore(add(m, 0xa0), add(s, returndatasize())) o := add(o, returndatasize()) n := add(0x20, mload(data)) pop(staticcall(gas(), 4, data, n, o, n)) n := sub(add(o, returndatasize()), add(m, 0x1c)) // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), n, m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xbc197c81))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } /// @dev Returns `x` in an array with a single element. function _single(uint256 x) private pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) mstore(0x40, add(result, 0x40)) mstore(result, 1) mstore(add(result, 0x20), x) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) /// /// Note: /// For performance and bytecode compactness, most of the string operations are restricted to /// byte strings (7-bit ASCII), except where otherwise specified. /// Usage of byte string operations on charsets with runes spanning two or more bytes /// can lead to undefined behavior. library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The length of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /// @dev The length of the string is more than 32 bytes. error TooBigForSmallString(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. str := add(mload(0x40), 0x80) // Update the free memory pointer to allocate. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 1)`. // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory str) { if (value >= 0) { return toString(uint256(value)); } unchecked { str = toString(uint256(-value)); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let length := mload(str) // Load the string length. mstore(str, 0x2d) // Store the '-' character. str := sub(str, 1) // Move back the string pointer by a byte. mstore(str, add(length, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2 + 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) { str = toHexStringNoPrefix(value, length); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(str, add(length, length)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(str, start)) { break } } if temp { mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. revert(0x1c, 0x04) } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := add(mload(str), 2) // Compute the length. mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero. str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := mload(str) // Get the length. str := add(str, o) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. str := add(mload(0x40), 0x80) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let o := add(str, 0x20) let end := add(raw, length) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let mask := shl(7, div(not(0), 255)) result := 1 let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, byte string operations are restricted // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. // Usage of byte string operations on charsets with runes spanning two or more bytes // can lead to undefined behavior. /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`. function replace(string memory subject, string memory search, string memory replacement) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) let replacementLength := mload(replacement) subject := add(subject, 0x20) search := add(search, 0x20) replacement := add(replacement, 0x20) result := add(mload(0x40), 0x20) let subjectEnd := add(subject, subjectLength) if iszero(gt(searchLength, subjectLength)) { let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let o := 0 } 1 {} { mstore(add(result, o), mload(add(replacement, o))) o := add(o, 0x20) if iszero(lt(o, replacementLength)) { break } } result := add(result, replacementLength) subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } } let resultRemainder := result result := add(mload(0x40), 0x20) let k := add(sub(resultRemainder, result), sub(subjectEnd, subject)) // Copy the rest of the string one word at a time. for {} lt(subject, subjectEnd) {} { mstore(resultRemainder, mload(subject)) resultRemainder := add(resultRemainder, 0x20) subject := add(subject, 0x20) } result := sub(result, 0x20) let last := add(add(result, 0x20), k) // Zeroize the slot after the string. mstore(last, 0) mstore(0x40, add(last, 0x20)) // Allocate the memory. mstore(result, k) // Store the length. } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for { let subjectLength := mload(subject) } 1 {} { if iszero(mload(search)) { if iszero(gt(from, subjectLength)) { result := from break } result := subjectLength break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(add(search, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } if iszero(lt(searchLength, 0x20)) { for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, searchLength), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = indexOf(subject, search, 0); } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let searchLength := mload(search) if gt(searchLength, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if eq(keccak256(subject, searchLength), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = lastIndexOf(subject, search, uint256(int256(-1))); } /// @dev Returns true if `search` is found in `subject`, false otherwise. function contains(string memory subject, string memory search) internal pure returns (bool) { return indexOf(subject, search) != NOT_FOUND; } /// @dev Returns whether `subject` starts with `search`. function startsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( iszero(gt(searchLength, mload(subject))), eq( keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns whether `subject` ends with `search`. function endsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) let subjectLength := mload(subject) // Whether `search` is not longer than `subject`. let withinRange := iszero(gt(searchLength, subjectLength)) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( withinRange, eq( keccak256( // `subject + 0x20 + max(subjectLength - searchLength, 0)`. add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))), searchLength ), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(or(iszero(times), iszero(subjectLength))) { subject := add(subject, 0x20) result := mload(0x40) let output := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let o := 0 } 1 {} { mstore(add(output, o), mload(add(subject, o))) o := add(o, 0x20) if iszero(lt(o, subjectLength)) { break } } output := add(output, subjectLength) times := sub(times, 1) if iszero(times) { break } } mstore(output, 0) // Zeroize the slot after the string. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Store the length. // Allocate the memory. mstore(0x40, add(result, add(resultLength, 0x20))) } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(gt(subjectLength, end)) { end := subjectLength } if iszero(gt(subjectLength, start)) { start := subjectLength } if lt(start, end) { result := mload(0x40) let resultLength := sub(end, start) mstore(result, resultLength) subject := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 0x1f), w) } 1 {} { mstore(add(result, o), mload(add(subject, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(result, 0x20), resultLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 0x3f), w))) } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory result) { result = slice(subject, start, uint256(int256(-1))); } /// @dev Returns all the indices of `search` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) if iszero(gt(searchLength, subjectLength)) { subject := add(subject, 0x20) search := add(search, 0x20) result := add(mload(0x40), 0x20) let subjectStart := subject let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Append to `result`. mstore(result, sub(subject, subjectStart)) result := add(result, 0x20) // Advance `subject` by `searchLength`. subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } let resultEnd := result // Assign `result` to the free memory pointer. result := mload(0x40) // Store the length of `result`. mstore(result, shr(5, sub(resultEnd, add(result, 0x20)))) // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(resultEnd, 0x20)) } } } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) let prevIndex := 0 for {} 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let elementLength := sub(index, prevIndex) mstore(element, elementLength) // Copy the `subject` one word at a time, backwards. for { let o := and(add(elementLength, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(element, 0x20), elementLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(element, and(add(elementLength, 0x3f), w))) // Store the `element` into the array. mstore(indexPtr, element) } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let w := not(0x1f) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLength, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLength := mload(b) let output := add(result, aLength) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLength := add(aLength, bLength) let last := add(add(result, 0x20), totalLength) // Zeroize the slot after the string. mstore(last, 0) // Stores the length. mstore(result, totalLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 0x1f), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let length := mload(subject) if length { result := add(mload(0x40), 0x20) subject := add(subject, 1) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) let w := not(0) for { let o := length } 1 {} { o := add(o, w) let b := and(0xff, mload(add(subject, o))) mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) if iszero(o) { break } } result := mload(0x40) mstore(result, length) // Store the length. let last := add(add(result, 0x20), length) mstore(last, 0) // Zeroize the slot after the string. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } } /// @dev Returns a string from a small bytes32 string. /// `s` must be null-terminated, or behavior will be undefined. function fromSmallString(bytes32 s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'. mstore(result, n) let o := add(result, 0x20) mstore(o, s) mstore(add(o, n), 0) mstore(0x40, add(result, 0x40)) } } /// @dev Returns the small string, with all bytes after the first null byte zeroized. function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'. mstore(0x00, s) mstore(result, 0x00) result := mload(0x00) } } /// @dev Returns the string as a normalized null-terminated small string. function toSmallString(string memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(s) if iszero(lt(result, 33)) { mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. revert(0x1c, 0x04) } result := shl(shl(3, sub(32, result)), mload(add(s, result))) } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(result, c) result := add(result, 1) continue } let t := shr(248, mload(c)) mstore(result, mload(and(t, 0x1f))) result := add(result, shr(5, t)) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(result, c) result := add(result, 1) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), c) result := add(result, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(result, mload(0x19)) // "\\u00XX". result := add(result, 6) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), mload(add(c, 8))) result := add(result, 2) } if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behavior is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. result := mload(0x40) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(0x40, add(result, 0x40)) // Zeroize the length slot. mstore(result, 0) // Store the length and bytes. mstore(add(result, 0x1f), packed) // Right pad with zeroes. mstore(add(add(result, 0x20), mload(result)), 0) } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLength := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes of `a` and `b`. or( shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength)) ), // `totalLength != 0 && totalLength < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLength, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behavior is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. resultA := mload(0x40) resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retSize := 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, retSize), 0) // Store the return offset. mstore(retStart, 0x20) // End the transaction, returning the string. return(retStart, retSize) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev Cannot double-initialize. error AlreadyInitialized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. bytes32 internal constant _OWNER_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return true to make `_initializeOwner` prevent double-initialization. function _guardInitializeOwner() internal pure virtual returns (bool guard) {} /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT if sload(ownerSlot) { mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`. revert(0x1c, 0x04) } // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } else { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(_OWNER_SLOT, newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) } } else { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(_OWNER_SLOT))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(_OWNER_SLOT) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
// SPDX-License-Identifier: BUSL-1.1 // // ↑↑↑↑ ↑↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑ ↑ // ↑↑↑↑ ↑↑↑↑↑ // ↑ ↑↑↑↑ ↑ ↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑↑ ↑↑ ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ ↑↑ ↑↑↑ ↑↑↑↑↑↑ ↑↑↑↑↑↑ ↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑ ↑↑↑ // ↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑ Starport: Lending Kernel // ↑ ↑↑↑↑ ↑↑↑↑↑ // ↑↑↑↑ ↑↑↑↑↑ Designed with love by Astaria Labs, Inc // ↑↑↑↑ ↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ // ↑↑↑↑ pragma solidity ^0.8.17; import {Starport} from "../Starport.sol"; abstract contract Validation { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /* * @dev Validates the loan against the module * @param loan The loan to validate * @return bytes4 The validation result */ function validate(Starport.Loan calldata) external view virtual returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; enum OrderType { // 0: no partial fills, anyone can execute FULL_OPEN, // 1: partial fills supported, anyone can execute PARTIAL_OPEN, // 2: no partial fills, only offerer or zone can execute FULL_RESTRICTED, // 3: partial fills supported, only offerer or zone can execute PARTIAL_RESTRICTED, // 4: contract order type CONTRACT } enum BasicOrderType { // 0: no partial fills, anyone can execute ETH_TO_ERC721_FULL_OPEN, // 1: partial fills supported, anyone can execute ETH_TO_ERC721_PARTIAL_OPEN, // 2: no partial fills, only offerer or zone can execute ETH_TO_ERC721_FULL_RESTRICTED, // 3: partial fills supported, only offerer or zone can execute ETH_TO_ERC721_PARTIAL_RESTRICTED, // 4: no partial fills, anyone can execute ETH_TO_ERC1155_FULL_OPEN, // 5: partial fills supported, anyone can execute ETH_TO_ERC1155_PARTIAL_OPEN, // 6: no partial fills, only offerer or zone can execute ETH_TO_ERC1155_FULL_RESTRICTED, // 7: partial fills supported, only offerer or zone can execute ETH_TO_ERC1155_PARTIAL_RESTRICTED, // 8: no partial fills, anyone can execute ERC20_TO_ERC721_FULL_OPEN, // 9: partial fills supported, anyone can execute ERC20_TO_ERC721_PARTIAL_OPEN, // 10: no partial fills, only offerer or zone can execute ERC20_TO_ERC721_FULL_RESTRICTED, // 11: partial fills supported, only offerer or zone can execute ERC20_TO_ERC721_PARTIAL_RESTRICTED, // 12: no partial fills, anyone can execute ERC20_TO_ERC1155_FULL_OPEN, // 13: partial fills supported, anyone can execute ERC20_TO_ERC1155_PARTIAL_OPEN, // 14: no partial fills, only offerer or zone can execute ERC20_TO_ERC1155_FULL_RESTRICTED, // 15: partial fills supported, only offerer or zone can execute ERC20_TO_ERC1155_PARTIAL_RESTRICTED, // 16: no partial fills, anyone can execute ERC721_TO_ERC20_FULL_OPEN, // 17: partial fills supported, anyone can execute ERC721_TO_ERC20_PARTIAL_OPEN, // 18: no partial fills, only offerer or zone can execute ERC721_TO_ERC20_FULL_RESTRICTED, // 19: partial fills supported, only offerer or zone can execute ERC721_TO_ERC20_PARTIAL_RESTRICTED, // 20: no partial fills, anyone can execute ERC1155_TO_ERC20_FULL_OPEN, // 21: partial fills supported, anyone can execute ERC1155_TO_ERC20_PARTIAL_OPEN, // 22: no partial fills, only offerer or zone can execute ERC1155_TO_ERC20_FULL_RESTRICTED, // 23: partial fills supported, only offerer or zone can execute ERC1155_TO_ERC20_PARTIAL_RESTRICTED } enum BasicOrderRouteType { // 0: provide Ether (or other native token) to receive offered ERC721 item. ETH_TO_ERC721, // 1: provide Ether (or other native token) to receive offered ERC1155 item. ETH_TO_ERC1155, // 2: provide ERC20 item to receive offered ERC721 item. ERC20_TO_ERC721, // 3: provide ERC20 item to receive offered ERC1155 item. ERC20_TO_ERC1155, // 4: provide ERC721 item to receive offered ERC20 item. ERC721_TO_ERC20, // 5: provide ERC1155 item to receive offered ERC20 item. ERC1155_TO_ERC20 } enum ItemType { // 0: ETH on mainnet, MATIC on polygon, etc. NATIVE, // 1: ERC20 items (ERC777 and ERC20 analogues could also technically work) ERC20, // 2: ERC721 items ERC721, // 3: ERC1155 items ERC1155, // 4: ERC721 items where a number of tokenIds are supported ERC721_WITH_CRITERIA, // 5: ERC1155 items where a number of ids are supported ERC1155_WITH_CRITERIA } enum Side { // 0: Items that can be spent OFFER, // 1: Items that must be received CONSIDERATION }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; type CalldataPointer is uint256; type ReturndataPointer is uint256; type MemoryPointer is uint256; using CalldataPointerLib for CalldataPointer global; using MemoryPointerLib for MemoryPointer global; using ReturndataPointerLib for ReturndataPointer global; using CalldataReaders for CalldataPointer global; using ReturndataReaders for ReturndataPointer global; using MemoryReaders for MemoryPointer global; using MemoryWriters for MemoryPointer global; CalldataPointer constant CalldataStart = CalldataPointer.wrap(0x04); MemoryPointer constant FreeMemoryPPtr = MemoryPointer.wrap(0x40); uint256 constant IdentityPrecompileAddress = 0x4; uint256 constant OffsetOrLengthMask = 0xffffffff; uint256 constant _OneWord = 0x20; uint256 constant _FreeMemoryPointerSlot = 0x40; /// @dev Allocates `size` bytes in memory by increasing the free memory pointer /// and returns the memory pointer to the first byte of the allocated region. // (Free functions cannot have visibility.) // solhint-disable-next-line func-visibility function malloc(uint256 size) pure returns (MemoryPointer mPtr) { assembly { mPtr := mload(_FreeMemoryPointerSlot) mstore(_FreeMemoryPointerSlot, add(mPtr, size)) } } // (Free functions cannot have visibility.) // solhint-disable-next-line func-visibility function getFreeMemoryPointer() pure returns (MemoryPointer mPtr) { mPtr = FreeMemoryPPtr.readMemoryPointer(); } // (Free functions cannot have visibility.) // solhint-disable-next-line func-visibility function setFreeMemoryPointer(MemoryPointer mPtr) pure { FreeMemoryPPtr.write(mPtr); } library CalldataPointerLib { function lt( CalldataPointer a, CalldataPointer b ) internal pure returns (bool c) { assembly { c := lt(a, b) } } function gt( CalldataPointer a, CalldataPointer b ) internal pure returns (bool c) { assembly { c := gt(a, b) } } function eq( CalldataPointer a, CalldataPointer b ) internal pure returns (bool c) { assembly { c := eq(a, b) } } function isNull(CalldataPointer a) internal pure returns (bool b) { assembly { b := iszero(a) } } /// @dev Resolves an offset stored at `cdPtr + headOffset` to a calldata. /// pointer `cdPtr` must point to some parent object with a dynamic /// type's head stored at `cdPtr + headOffset`. function pptr( CalldataPointer cdPtr, uint256 headOffset ) internal pure returns (CalldataPointer cdPtrChild) { cdPtrChild = cdPtr.offset( cdPtr.offset(headOffset).readUint256() & OffsetOrLengthMask ); } /// @dev Resolves an offset stored at `cdPtr` to a calldata pointer. /// `cdPtr` must point to some parent object with a dynamic type as its /// first member, e.g. `struct { bytes data; }` function pptr( CalldataPointer cdPtr ) internal pure returns (CalldataPointer cdPtrChild) { cdPtrChild = cdPtr.offset(cdPtr.readUint256() & OffsetOrLengthMask); } /// @dev Returns the calldata pointer one word after `cdPtr`. function next( CalldataPointer cdPtr ) internal pure returns (CalldataPointer cdPtrNext) { assembly { cdPtrNext := add(cdPtr, _OneWord) } } /// @dev Returns the calldata pointer `_offset` bytes after `cdPtr`. function offset( CalldataPointer cdPtr, uint256 _offset ) internal pure returns (CalldataPointer cdPtrNext) { assembly { cdPtrNext := add(cdPtr, _offset) } } /// @dev Copies `size` bytes from calldata starting at `src` to memory at /// `dst`. function copy( CalldataPointer src, MemoryPointer dst, uint256 size ) internal pure { assembly { calldatacopy(dst, src, size) } } } library ReturndataPointerLib { function lt( ReturndataPointer a, ReturndataPointer b ) internal pure returns (bool c) { assembly { c := lt(a, b) } } function gt( ReturndataPointer a, ReturndataPointer b ) internal pure returns (bool c) { assembly { c := gt(a, b) } } function eq( ReturndataPointer a, ReturndataPointer b ) internal pure returns (bool c) { assembly { c := eq(a, b) } } function isNull(ReturndataPointer a) internal pure returns (bool b) { assembly { b := iszero(a) } } /// @dev Resolves an offset stored at `rdPtr + headOffset` to a returndata /// pointer. `rdPtr` must point to some parent object with a dynamic /// type's head stored at `rdPtr + headOffset`. function pptr( ReturndataPointer rdPtr, uint256 headOffset ) internal pure returns (ReturndataPointer rdPtrChild) { rdPtrChild = rdPtr.offset( rdPtr.offset(headOffset).readUint256() & OffsetOrLengthMask ); } /// @dev Resolves an offset stored at `rdPtr` to a returndata pointer. /// `rdPtr` must point to some parent object with a dynamic type as its /// first member, e.g. `struct { bytes data; }` function pptr( ReturndataPointer rdPtr ) internal pure returns (ReturndataPointer rdPtrChild) { rdPtrChild = rdPtr.offset(rdPtr.readUint256() & OffsetOrLengthMask); } /// @dev Returns the returndata pointer one word after `cdPtr`. function next( ReturndataPointer rdPtr ) internal pure returns (ReturndataPointer rdPtrNext) { assembly { rdPtrNext := add(rdPtr, _OneWord) } } /// @dev Returns the returndata pointer `_offset` bytes after `cdPtr`. function offset( ReturndataPointer rdPtr, uint256 _offset ) internal pure returns (ReturndataPointer rdPtrNext) { assembly { rdPtrNext := add(rdPtr, _offset) } } /// @dev Copies `size` bytes from returndata starting at `src` to memory at /// `dst`. function copy( ReturndataPointer src, MemoryPointer dst, uint256 size ) internal pure { assembly { returndatacopy(dst, src, size) } } } library MemoryPointerLib { function copy( MemoryPointer src, MemoryPointer dst, uint256 size ) internal view { assembly { let success := staticcall( gas(), IdentityPrecompileAddress, src, size, dst, size ) if or(iszero(returndatasize()), iszero(success)) { revert(0, 0) } } } function lt( MemoryPointer a, MemoryPointer b ) internal pure returns (bool c) { assembly { c := lt(a, b) } } function gt( MemoryPointer a, MemoryPointer b ) internal pure returns (bool c) { assembly { c := gt(a, b) } } function eq( MemoryPointer a, MemoryPointer b ) internal pure returns (bool c) { assembly { c := eq(a, b) } } function isNull(MemoryPointer a) internal pure returns (bool b) { assembly { b := iszero(a) } } function hash( MemoryPointer ptr, uint256 length ) internal pure returns (bytes32 _hash) { assembly { _hash := keccak256(ptr, length) } } /// @dev Returns the memory pointer one word after `mPtr`. function next( MemoryPointer mPtr ) internal pure returns (MemoryPointer mPtrNext) { assembly { mPtrNext := add(mPtr, _OneWord) } } /// @dev Returns the memory pointer `_offset` bytes after `mPtr`. function offset( MemoryPointer mPtr, uint256 _offset ) internal pure returns (MemoryPointer mPtrNext) { assembly { mPtrNext := add(mPtr, _offset) } } /// @dev Resolves a pointer at `mPtr + headOffset` to a memory /// pointer. `mPtr` must point to some parent object with a dynamic /// type's pointer stored at `mPtr + headOffset`. function pptr( MemoryPointer mPtr, uint256 headOffset ) internal pure returns (MemoryPointer mPtrChild) { mPtrChild = mPtr.offset(headOffset).readMemoryPointer(); } /// @dev Resolves a pointer stored at `mPtr` to a memory pointer. /// `mPtr` must point to some parent object with a dynamic type as its /// first member, e.g. `struct { bytes data; }` function pptr( MemoryPointer mPtr ) internal pure returns (MemoryPointer mPtrChild) { mPtrChild = mPtr.readMemoryPointer(); } } library CalldataReaders { /// @dev Reads the value at `cdPtr` and applies a mask to return only the /// last 4 bytes. function readMaskedUint256( CalldataPointer cdPtr ) internal pure returns (uint256 value) { value = cdPtr.readUint256() & OffsetOrLengthMask; } /// @dev Reads the bool at `cdPtr` in calldata. function readBool( CalldataPointer cdPtr ) internal pure returns (bool value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the address at `cdPtr` in calldata. function readAddress( CalldataPointer cdPtr ) internal pure returns (address value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes1 at `cdPtr` in calldata. function readBytes1( CalldataPointer cdPtr ) internal pure returns (bytes1 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes2 at `cdPtr` in calldata. function readBytes2( CalldataPointer cdPtr ) internal pure returns (bytes2 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes3 at `cdPtr` in calldata. function readBytes3( CalldataPointer cdPtr ) internal pure returns (bytes3 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes4 at `cdPtr` in calldata. function readBytes4( CalldataPointer cdPtr ) internal pure returns (bytes4 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes5 at `cdPtr` in calldata. function readBytes5( CalldataPointer cdPtr ) internal pure returns (bytes5 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes6 at `cdPtr` in calldata. function readBytes6( CalldataPointer cdPtr ) internal pure returns (bytes6 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes7 at `cdPtr` in calldata. function readBytes7( CalldataPointer cdPtr ) internal pure returns (bytes7 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes8 at `cdPtr` in calldata. function readBytes8( CalldataPointer cdPtr ) internal pure returns (bytes8 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes9 at `cdPtr` in calldata. function readBytes9( CalldataPointer cdPtr ) internal pure returns (bytes9 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes10 at `cdPtr` in calldata. function readBytes10( CalldataPointer cdPtr ) internal pure returns (bytes10 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes11 at `cdPtr` in calldata. function readBytes11( CalldataPointer cdPtr ) internal pure returns (bytes11 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes12 at `cdPtr` in calldata. function readBytes12( CalldataPointer cdPtr ) internal pure returns (bytes12 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes13 at `cdPtr` in calldata. function readBytes13( CalldataPointer cdPtr ) internal pure returns (bytes13 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes14 at `cdPtr` in calldata. function readBytes14( CalldataPointer cdPtr ) internal pure returns (bytes14 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes15 at `cdPtr` in calldata. function readBytes15( CalldataPointer cdPtr ) internal pure returns (bytes15 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes16 at `cdPtr` in calldata. function readBytes16( CalldataPointer cdPtr ) internal pure returns (bytes16 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes17 at `cdPtr` in calldata. function readBytes17( CalldataPointer cdPtr ) internal pure returns (bytes17 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes18 at `cdPtr` in calldata. function readBytes18( CalldataPointer cdPtr ) internal pure returns (bytes18 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes19 at `cdPtr` in calldata. function readBytes19( CalldataPointer cdPtr ) internal pure returns (bytes19 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes20 at `cdPtr` in calldata. function readBytes20( CalldataPointer cdPtr ) internal pure returns (bytes20 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes21 at `cdPtr` in calldata. function readBytes21( CalldataPointer cdPtr ) internal pure returns (bytes21 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes22 at `cdPtr` in calldata. function readBytes22( CalldataPointer cdPtr ) internal pure returns (bytes22 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes23 at `cdPtr` in calldata. function readBytes23( CalldataPointer cdPtr ) internal pure returns (bytes23 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes24 at `cdPtr` in calldata. function readBytes24( CalldataPointer cdPtr ) internal pure returns (bytes24 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes25 at `cdPtr` in calldata. function readBytes25( CalldataPointer cdPtr ) internal pure returns (bytes25 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes26 at `cdPtr` in calldata. function readBytes26( CalldataPointer cdPtr ) internal pure returns (bytes26 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes27 at `cdPtr` in calldata. function readBytes27( CalldataPointer cdPtr ) internal pure returns (bytes27 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes28 at `cdPtr` in calldata. function readBytes28( CalldataPointer cdPtr ) internal pure returns (bytes28 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes29 at `cdPtr` in calldata. function readBytes29( CalldataPointer cdPtr ) internal pure returns (bytes29 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes30 at `cdPtr` in calldata. function readBytes30( CalldataPointer cdPtr ) internal pure returns (bytes30 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes31 at `cdPtr` in calldata. function readBytes31( CalldataPointer cdPtr ) internal pure returns (bytes31 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes32 at `cdPtr` in calldata. function readBytes32( CalldataPointer cdPtr ) internal pure returns (bytes32 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint8 at `cdPtr` in calldata. function readUint8( CalldataPointer cdPtr ) internal pure returns (uint8 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint16 at `cdPtr` in calldata. function readUint16( CalldataPointer cdPtr ) internal pure returns (uint16 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint24 at `cdPtr` in calldata. function readUint24( CalldataPointer cdPtr ) internal pure returns (uint24 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint32 at `cdPtr` in calldata. function readUint32( CalldataPointer cdPtr ) internal pure returns (uint32 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint40 at `cdPtr` in calldata. function readUint40( CalldataPointer cdPtr ) internal pure returns (uint40 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint48 at `cdPtr` in calldata. function readUint48( CalldataPointer cdPtr ) internal pure returns (uint48 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint56 at `cdPtr` in calldata. function readUint56( CalldataPointer cdPtr ) internal pure returns (uint56 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint64 at `cdPtr` in calldata. function readUint64( CalldataPointer cdPtr ) internal pure returns (uint64 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint72 at `cdPtr` in calldata. function readUint72( CalldataPointer cdPtr ) internal pure returns (uint72 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint80 at `cdPtr` in calldata. function readUint80( CalldataPointer cdPtr ) internal pure returns (uint80 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint88 at `cdPtr` in calldata. function readUint88( CalldataPointer cdPtr ) internal pure returns (uint88 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint96 at `cdPtr` in calldata. function readUint96( CalldataPointer cdPtr ) internal pure returns (uint96 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint104 at `cdPtr` in calldata. function readUint104( CalldataPointer cdPtr ) internal pure returns (uint104 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint112 at `cdPtr` in calldata. function readUint112( CalldataPointer cdPtr ) internal pure returns (uint112 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint120 at `cdPtr` in calldata. function readUint120( CalldataPointer cdPtr ) internal pure returns (uint120 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint128 at `cdPtr` in calldata. function readUint128( CalldataPointer cdPtr ) internal pure returns (uint128 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint136 at `cdPtr` in calldata. function readUint136( CalldataPointer cdPtr ) internal pure returns (uint136 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint144 at `cdPtr` in calldata. function readUint144( CalldataPointer cdPtr ) internal pure returns (uint144 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint152 at `cdPtr` in calldata. function readUint152( CalldataPointer cdPtr ) internal pure returns (uint152 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint160 at `cdPtr` in calldata. function readUint160( CalldataPointer cdPtr ) internal pure returns (uint160 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint168 at `cdPtr` in calldata. function readUint168( CalldataPointer cdPtr ) internal pure returns (uint168 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint176 at `cdPtr` in calldata. function readUint176( CalldataPointer cdPtr ) internal pure returns (uint176 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint184 at `cdPtr` in calldata. function readUint184( CalldataPointer cdPtr ) internal pure returns (uint184 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint192 at `cdPtr` in calldata. function readUint192( CalldataPointer cdPtr ) internal pure returns (uint192 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint200 at `cdPtr` in calldata. function readUint200( CalldataPointer cdPtr ) internal pure returns (uint200 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint208 at `cdPtr` in calldata. function readUint208( CalldataPointer cdPtr ) internal pure returns (uint208 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint216 at `cdPtr` in calldata. function readUint216( CalldataPointer cdPtr ) internal pure returns (uint216 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint224 at `cdPtr` in calldata. function readUint224( CalldataPointer cdPtr ) internal pure returns (uint224 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint232 at `cdPtr` in calldata. function readUint232( CalldataPointer cdPtr ) internal pure returns (uint232 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint240 at `cdPtr` in calldata. function readUint240( CalldataPointer cdPtr ) internal pure returns (uint240 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint248 at `cdPtr` in calldata. function readUint248( CalldataPointer cdPtr ) internal pure returns (uint248 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint256 at `cdPtr` in calldata. function readUint256( CalldataPointer cdPtr ) internal pure returns (uint256 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int8 at `cdPtr` in calldata. function readInt8( CalldataPointer cdPtr ) internal pure returns (int8 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int16 at `cdPtr` in calldata. function readInt16( CalldataPointer cdPtr ) internal pure returns (int16 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int24 at `cdPtr` in calldata. function readInt24( CalldataPointer cdPtr ) internal pure returns (int24 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int32 at `cdPtr` in calldata. function readInt32( CalldataPointer cdPtr ) internal pure returns (int32 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int40 at `cdPtr` in calldata. function readInt40( CalldataPointer cdPtr ) internal pure returns (int40 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int48 at `cdPtr` in calldata. function readInt48( CalldataPointer cdPtr ) internal pure returns (int48 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int56 at `cdPtr` in calldata. function readInt56( CalldataPointer cdPtr ) internal pure returns (int56 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int64 at `cdPtr` in calldata. function readInt64( CalldataPointer cdPtr ) internal pure returns (int64 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int72 at `cdPtr` in calldata. function readInt72( CalldataPointer cdPtr ) internal pure returns (int72 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int80 at `cdPtr` in calldata. function readInt80( CalldataPointer cdPtr ) internal pure returns (int80 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int88 at `cdPtr` in calldata. function readInt88( CalldataPointer cdPtr ) internal pure returns (int88 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int96 at `cdPtr` in calldata. function readInt96( CalldataPointer cdPtr ) internal pure returns (int96 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int104 at `cdPtr` in calldata. function readInt104( CalldataPointer cdPtr ) internal pure returns (int104 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int112 at `cdPtr` in calldata. function readInt112( CalldataPointer cdPtr ) internal pure returns (int112 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int120 at `cdPtr` in calldata. function readInt120( CalldataPointer cdPtr ) internal pure returns (int120 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int128 at `cdPtr` in calldata. function readInt128( CalldataPointer cdPtr ) internal pure returns (int128 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int136 at `cdPtr` in calldata. function readInt136( CalldataPointer cdPtr ) internal pure returns (int136 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int144 at `cdPtr` in calldata. function readInt144( CalldataPointer cdPtr ) internal pure returns (int144 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int152 at `cdPtr` in calldata. function readInt152( CalldataPointer cdPtr ) internal pure returns (int152 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int160 at `cdPtr` in calldata. function readInt160( CalldataPointer cdPtr ) internal pure returns (int160 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int168 at `cdPtr` in calldata. function readInt168( CalldataPointer cdPtr ) internal pure returns (int168 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int176 at `cdPtr` in calldata. function readInt176( CalldataPointer cdPtr ) internal pure returns (int176 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int184 at `cdPtr` in calldata. function readInt184( CalldataPointer cdPtr ) internal pure returns (int184 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int192 at `cdPtr` in calldata. function readInt192( CalldataPointer cdPtr ) internal pure returns (int192 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int200 at `cdPtr` in calldata. function readInt200( CalldataPointer cdPtr ) internal pure returns (int200 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int208 at `cdPtr` in calldata. function readInt208( CalldataPointer cdPtr ) internal pure returns (int208 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int216 at `cdPtr` in calldata. function readInt216( CalldataPointer cdPtr ) internal pure returns (int216 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int224 at `cdPtr` in calldata. function readInt224( CalldataPointer cdPtr ) internal pure returns (int224 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int232 at `cdPtr` in calldata. function readInt232( CalldataPointer cdPtr ) internal pure returns (int232 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int240 at `cdPtr` in calldata. function readInt240( CalldataPointer cdPtr ) internal pure returns (int240 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int248 at `cdPtr` in calldata. function readInt248( CalldataPointer cdPtr ) internal pure returns (int248 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int256 at `cdPtr` in calldata. function readInt256( CalldataPointer cdPtr ) internal pure returns (int256 value) { assembly { value := calldataload(cdPtr) } } } library ReturndataReaders { /// @dev Reads value at `rdPtr` & applies a mask to return only last 4 bytes function readMaskedUint256( ReturndataPointer rdPtr ) internal pure returns (uint256 value) { value = rdPtr.readUint256() & OffsetOrLengthMask; } /// @dev Reads the bool at `rdPtr` in returndata. function readBool( ReturndataPointer rdPtr ) internal pure returns (bool value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the address at `rdPtr` in returndata. function readAddress( ReturndataPointer rdPtr ) internal pure returns (address value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes1 at `rdPtr` in returndata. function readBytes1( ReturndataPointer rdPtr ) internal pure returns (bytes1 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes2 at `rdPtr` in returndata. function readBytes2( ReturndataPointer rdPtr ) internal pure returns (bytes2 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes3 at `rdPtr` in returndata. function readBytes3( ReturndataPointer rdPtr ) internal pure returns (bytes3 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes4 at `rdPtr` in returndata. function readBytes4( ReturndataPointer rdPtr ) internal pure returns (bytes4 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes5 at `rdPtr` in returndata. function readBytes5( ReturndataPointer rdPtr ) internal pure returns (bytes5 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes6 at `rdPtr` in returndata. function readBytes6( ReturndataPointer rdPtr ) internal pure returns (bytes6 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes7 at `rdPtr` in returndata. function readBytes7( ReturndataPointer rdPtr ) internal pure returns (bytes7 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes8 at `rdPtr` in returndata. function readBytes8( ReturndataPointer rdPtr ) internal pure returns (bytes8 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes9 at `rdPtr` in returndata. function readBytes9( ReturndataPointer rdPtr ) internal pure returns (bytes9 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes10 at `rdPtr` in returndata. function readBytes10( ReturndataPointer rdPtr ) internal pure returns (bytes10 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes11 at `rdPtr` in returndata. function readBytes11( ReturndataPointer rdPtr ) internal pure returns (bytes11 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes12 at `rdPtr` in returndata. function readBytes12( ReturndataPointer rdPtr ) internal pure returns (bytes12 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes13 at `rdPtr` in returndata. function readBytes13( ReturndataPointer rdPtr ) internal pure returns (bytes13 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes14 at `rdPtr` in returndata. function readBytes14( ReturndataPointer rdPtr ) internal pure returns (bytes14 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes15 at `rdPtr` in returndata. function readBytes15( ReturndataPointer rdPtr ) internal pure returns (bytes15 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes16 at `rdPtr` in returndata. function readBytes16( ReturndataPointer rdPtr ) internal pure returns (bytes16 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes17 at `rdPtr` in returndata. function readBytes17( ReturndataPointer rdPtr ) internal pure returns (bytes17 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes18 at `rdPtr` in returndata. function readBytes18( ReturndataPointer rdPtr ) internal pure returns (bytes18 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes19 at `rdPtr` in returndata. function readBytes19( ReturndataPointer rdPtr ) internal pure returns (bytes19 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes20 at `rdPtr` in returndata. function readBytes20( ReturndataPointer rdPtr ) internal pure returns (bytes20 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes21 at `rdPtr` in returndata. function readBytes21( ReturndataPointer rdPtr ) internal pure returns (bytes21 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes22 at `rdPtr` in returndata. function readBytes22( ReturndataPointer rdPtr ) internal pure returns (bytes22 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes23 at `rdPtr` in returndata. function readBytes23( ReturndataPointer rdPtr ) internal pure returns (bytes23 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes24 at `rdPtr` in returndata. function readBytes24( ReturndataPointer rdPtr ) internal pure returns (bytes24 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes25 at `rdPtr` in returndata. function readBytes25( ReturndataPointer rdPtr ) internal pure returns (bytes25 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes26 at `rdPtr` in returndata. function readBytes26( ReturndataPointer rdPtr ) internal pure returns (bytes26 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes27 at `rdPtr` in returndata. function readBytes27( ReturndataPointer rdPtr ) internal pure returns (bytes27 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes28 at `rdPtr` in returndata. function readBytes28( ReturndataPointer rdPtr ) internal pure returns (bytes28 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes29 at `rdPtr` in returndata. function readBytes29( ReturndataPointer rdPtr ) internal pure returns (bytes29 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes30 at `rdPtr` in returndata. function readBytes30( ReturndataPointer rdPtr ) internal pure returns (bytes30 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes31 at `rdPtr` in returndata. function readBytes31( ReturndataPointer rdPtr ) internal pure returns (bytes31 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes32 at `rdPtr` in returndata. function readBytes32( ReturndataPointer rdPtr ) internal pure returns (bytes32 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint8 at `rdPtr` in returndata. function readUint8( ReturndataPointer rdPtr ) internal pure returns (uint8 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint16 at `rdPtr` in returndata. function readUint16( ReturndataPointer rdPtr ) internal pure returns (uint16 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint24 at `rdPtr` in returndata. function readUint24( ReturndataPointer rdPtr ) internal pure returns (uint24 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint32 at `rdPtr` in returndata. function readUint32( ReturndataPointer rdPtr ) internal pure returns (uint32 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint40 at `rdPtr` in returndata. function readUint40( ReturndataPointer rdPtr ) internal pure returns (uint40 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint48 at `rdPtr` in returndata. function readUint48( ReturndataPointer rdPtr ) internal pure returns (uint48 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint56 at `rdPtr` in returndata. function readUint56( ReturndataPointer rdPtr ) internal pure returns (uint56 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint64 at `rdPtr` in returndata. function readUint64( ReturndataPointer rdPtr ) internal pure returns (uint64 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint72 at `rdPtr` in returndata. function readUint72( ReturndataPointer rdPtr ) internal pure returns (uint72 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint80 at `rdPtr` in returndata. function readUint80( ReturndataPointer rdPtr ) internal pure returns (uint80 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint88 at `rdPtr` in returndata. function readUint88( ReturndataPointer rdPtr ) internal pure returns (uint88 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint96 at `rdPtr` in returndata. function readUint96( ReturndataPointer rdPtr ) internal pure returns (uint96 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint104 at `rdPtr` in returndata. function readUint104( ReturndataPointer rdPtr ) internal pure returns (uint104 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint112 at `rdPtr` in returndata. function readUint112( ReturndataPointer rdPtr ) internal pure returns (uint112 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint120 at `rdPtr` in returndata. function readUint120( ReturndataPointer rdPtr ) internal pure returns (uint120 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint128 at `rdPtr` in returndata. function readUint128( ReturndataPointer rdPtr ) internal pure returns (uint128 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint136 at `rdPtr` in returndata. function readUint136( ReturndataPointer rdPtr ) internal pure returns (uint136 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint144 at `rdPtr` in returndata. function readUint144( ReturndataPointer rdPtr ) internal pure returns (uint144 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint152 at `rdPtr` in returndata. function readUint152( ReturndataPointer rdPtr ) internal pure returns (uint152 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint160 at `rdPtr` in returndata. function readUint160( ReturndataPointer rdPtr ) internal pure returns (uint160 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint168 at `rdPtr` in returndata. function readUint168( ReturndataPointer rdPtr ) internal pure returns (uint168 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint176 at `rdPtr` in returndata. function readUint176( ReturndataPointer rdPtr ) internal pure returns (uint176 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint184 at `rdPtr` in returndata. function readUint184( ReturndataPointer rdPtr ) internal pure returns (uint184 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint192 at `rdPtr` in returndata. function readUint192( ReturndataPointer rdPtr ) internal pure returns (uint192 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint200 at `rdPtr` in returndata. function readUint200( ReturndataPointer rdPtr ) internal pure returns (uint200 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint208 at `rdPtr` in returndata. function readUint208( ReturndataPointer rdPtr ) internal pure returns (uint208 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint216 at `rdPtr` in returndata. function readUint216( ReturndataPointer rdPtr ) internal pure returns (uint216 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint224 at `rdPtr` in returndata. function readUint224( ReturndataPointer rdPtr ) internal pure returns (uint224 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint232 at `rdPtr` in returndata. function readUint232( ReturndataPointer rdPtr ) internal pure returns (uint232 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint240 at `rdPtr` in returndata. function readUint240( ReturndataPointer rdPtr ) internal pure returns (uint240 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint248 at `rdPtr` in returndata. function readUint248( ReturndataPointer rdPtr ) internal pure returns (uint248 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint256 at `rdPtr` in returndata. function readUint256( ReturndataPointer rdPtr ) internal pure returns (uint256 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int8 at `rdPtr` in returndata. function readInt8( ReturndataPointer rdPtr ) internal pure returns (int8 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int16 at `rdPtr` in returndata. function readInt16( ReturndataPointer rdPtr ) internal pure returns (int16 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int24 at `rdPtr` in returndata. function readInt24( ReturndataPointer rdPtr ) internal pure returns (int24 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int32 at `rdPtr` in returndata. function readInt32( ReturndataPointer rdPtr ) internal pure returns (int32 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int40 at `rdPtr` in returndata. function readInt40( ReturndataPointer rdPtr ) internal pure returns (int40 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int48 at `rdPtr` in returndata. function readInt48( ReturndataPointer rdPtr ) internal pure returns (int48 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int56 at `rdPtr` in returndata. function readInt56( ReturndataPointer rdPtr ) internal pure returns (int56 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int64 at `rdPtr` in returndata. function readInt64( ReturndataPointer rdPtr ) internal pure returns (int64 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int72 at `rdPtr` in returndata. function readInt72( ReturndataPointer rdPtr ) internal pure returns (int72 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int80 at `rdPtr` in returndata. function readInt80( ReturndataPointer rdPtr ) internal pure returns (int80 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int88 at `rdPtr` in returndata. function readInt88( ReturndataPointer rdPtr ) internal pure returns (int88 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int96 at `rdPtr` in returndata. function readInt96( ReturndataPointer rdPtr ) internal pure returns (int96 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int104 at `rdPtr` in returndata. function readInt104( ReturndataPointer rdPtr ) internal pure returns (int104 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int112 at `rdPtr` in returndata. function readInt112( ReturndataPointer rdPtr ) internal pure returns (int112 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int120 at `rdPtr` in returndata. function readInt120( ReturndataPointer rdPtr ) internal pure returns (int120 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int128 at `rdPtr` in returndata. function readInt128( ReturndataPointer rdPtr ) internal pure returns (int128 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int136 at `rdPtr` in returndata. function readInt136( ReturndataPointer rdPtr ) internal pure returns (int136 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int144 at `rdPtr` in returndata. function readInt144( ReturndataPointer rdPtr ) internal pure returns (int144 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int152 at `rdPtr` in returndata. function readInt152( ReturndataPointer rdPtr ) internal pure returns (int152 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int160 at `rdPtr` in returndata. function readInt160( ReturndataPointer rdPtr ) internal pure returns (int160 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int168 at `rdPtr` in returndata. function readInt168( ReturndataPointer rdPtr ) internal pure returns (int168 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int176 at `rdPtr` in returndata. function readInt176( ReturndataPointer rdPtr ) internal pure returns (int176 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int184 at `rdPtr` in returndata. function readInt184( ReturndataPointer rdPtr ) internal pure returns (int184 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int192 at `rdPtr` in returndata. function readInt192( ReturndataPointer rdPtr ) internal pure returns (int192 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int200 at `rdPtr` in returndata. function readInt200( ReturndataPointer rdPtr ) internal pure returns (int200 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int208 at `rdPtr` in returndata. function readInt208( ReturndataPointer rdPtr ) internal pure returns (int208 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int216 at `rdPtr` in returndata. function readInt216( ReturndataPointer rdPtr ) internal pure returns (int216 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int224 at `rdPtr` in returndata. function readInt224( ReturndataPointer rdPtr ) internal pure returns (int224 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int232 at `rdPtr` in returndata. function readInt232( ReturndataPointer rdPtr ) internal pure returns (int232 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int240 at `rdPtr` in returndata. function readInt240( ReturndataPointer rdPtr ) internal pure returns (int240 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int248 at `rdPtr` in returndata. function readInt248( ReturndataPointer rdPtr ) internal pure returns (int248 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int256 at `rdPtr` in returndata. function readInt256( ReturndataPointer rdPtr ) internal pure returns (int256 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } } library MemoryReaders { /// @dev Reads the memory pointer at `mPtr` in memory. function readMemoryPointer( MemoryPointer mPtr ) internal pure returns (MemoryPointer value) { assembly { value := mload(mPtr) } } /// @dev Reads value at `mPtr` & applies a mask to return only last 4 bytes function readMaskedUint256( MemoryPointer mPtr ) internal pure returns (uint256 value) { value = mPtr.readUint256() & OffsetOrLengthMask; } /// @dev Reads the bool at `mPtr` in memory. function readBool(MemoryPointer mPtr) internal pure returns (bool value) { assembly { value := mload(mPtr) } } /// @dev Reads the address at `mPtr` in memory. function readAddress( MemoryPointer mPtr ) internal pure returns (address value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes1 at `mPtr` in memory. function readBytes1( MemoryPointer mPtr ) internal pure returns (bytes1 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes2 at `mPtr` in memory. function readBytes2( MemoryPointer mPtr ) internal pure returns (bytes2 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes3 at `mPtr` in memory. function readBytes3( MemoryPointer mPtr ) internal pure returns (bytes3 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes4 at `mPtr` in memory. function readBytes4( MemoryPointer mPtr ) internal pure returns (bytes4 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes5 at `mPtr` in memory. function readBytes5( MemoryPointer mPtr ) internal pure returns (bytes5 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes6 at `mPtr` in memory. function readBytes6( MemoryPointer mPtr ) internal pure returns (bytes6 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes7 at `mPtr` in memory. function readBytes7( MemoryPointer mPtr ) internal pure returns (bytes7 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes8 at `mPtr` in memory. function readBytes8( MemoryPointer mPtr ) internal pure returns (bytes8 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes9 at `mPtr` in memory. function readBytes9( MemoryPointer mPtr ) internal pure returns (bytes9 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes10 at `mPtr` in memory. function readBytes10( MemoryPointer mPtr ) internal pure returns (bytes10 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes11 at `mPtr` in memory. function readBytes11( MemoryPointer mPtr ) internal pure returns (bytes11 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes12 at `mPtr` in memory. function readBytes12( MemoryPointer mPtr ) internal pure returns (bytes12 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes13 at `mPtr` in memory. function readBytes13( MemoryPointer mPtr ) internal pure returns (bytes13 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes14 at `mPtr` in memory. function readBytes14( MemoryPointer mPtr ) internal pure returns (bytes14 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes15 at `mPtr` in memory. function readBytes15( MemoryPointer mPtr ) internal pure returns (bytes15 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes16 at `mPtr` in memory. function readBytes16( MemoryPointer mPtr ) internal pure returns (bytes16 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes17 at `mPtr` in memory. function readBytes17( MemoryPointer mPtr ) internal pure returns (bytes17 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes18 at `mPtr` in memory. function readBytes18( MemoryPointer mPtr ) internal pure returns (bytes18 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes19 at `mPtr` in memory. function readBytes19( MemoryPointer mPtr ) internal pure returns (bytes19 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes20 at `mPtr` in memory. function readBytes20( MemoryPointer mPtr ) internal pure returns (bytes20 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes21 at `mPtr` in memory. function readBytes21( MemoryPointer mPtr ) internal pure returns (bytes21 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes22 at `mPtr` in memory. function readBytes22( MemoryPointer mPtr ) internal pure returns (bytes22 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes23 at `mPtr` in memory. function readBytes23( MemoryPointer mPtr ) internal pure returns (bytes23 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes24 at `mPtr` in memory. function readBytes24( MemoryPointer mPtr ) internal pure returns (bytes24 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes25 at `mPtr` in memory. function readBytes25( MemoryPointer mPtr ) internal pure returns (bytes25 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes26 at `mPtr` in memory. function readBytes26( MemoryPointer mPtr ) internal pure returns (bytes26 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes27 at `mPtr` in memory. function readBytes27( MemoryPointer mPtr ) internal pure returns (bytes27 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes28 at `mPtr` in memory. function readBytes28( MemoryPointer mPtr ) internal pure returns (bytes28 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes29 at `mPtr` in memory. function readBytes29( MemoryPointer mPtr ) internal pure returns (bytes29 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes30 at `mPtr` in memory. function readBytes30( MemoryPointer mPtr ) internal pure returns (bytes30 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes31 at `mPtr` in memory. function readBytes31( MemoryPointer mPtr ) internal pure returns (bytes31 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes32 at `mPtr` in memory. function readBytes32( MemoryPointer mPtr ) internal pure returns (bytes32 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint8 at `mPtr` in memory. function readUint8(MemoryPointer mPtr) internal pure returns (uint8 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint16 at `mPtr` in memory. function readUint16( MemoryPointer mPtr ) internal pure returns (uint16 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint24 at `mPtr` in memory. function readUint24( MemoryPointer mPtr ) internal pure returns (uint24 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint32 at `mPtr` in memory. function readUint32( MemoryPointer mPtr ) internal pure returns (uint32 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint40 at `mPtr` in memory. function readUint40( MemoryPointer mPtr ) internal pure returns (uint40 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint48 at `mPtr` in memory. function readUint48( MemoryPointer mPtr ) internal pure returns (uint48 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint56 at `mPtr` in memory. function readUint56( MemoryPointer mPtr ) internal pure returns (uint56 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint64 at `mPtr` in memory. function readUint64( MemoryPointer mPtr ) internal pure returns (uint64 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint72 at `mPtr` in memory. function readUint72( MemoryPointer mPtr ) internal pure returns (uint72 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint80 at `mPtr` in memory. function readUint80( MemoryPointer mPtr ) internal pure returns (uint80 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint88 at `mPtr` in memory. function readUint88( MemoryPointer mPtr ) internal pure returns (uint88 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint96 at `mPtr` in memory. function readUint96( MemoryPointer mPtr ) internal pure returns (uint96 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint104 at `mPtr` in memory. function readUint104( MemoryPointer mPtr ) internal pure returns (uint104 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint112 at `mPtr` in memory. function readUint112( MemoryPointer mPtr ) internal pure returns (uint112 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint120 at `mPtr` in memory. function readUint120( MemoryPointer mPtr ) internal pure returns (uint120 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint128 at `mPtr` in memory. function readUint128( MemoryPointer mPtr ) internal pure returns (uint128 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint136 at `mPtr` in memory. function readUint136( MemoryPointer mPtr ) internal pure returns (uint136 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint144 at `mPtr` in memory. function readUint144( MemoryPointer mPtr ) internal pure returns (uint144 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint152 at `mPtr` in memory. function readUint152( MemoryPointer mPtr ) internal pure returns (uint152 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint160 at `mPtr` in memory. function readUint160( MemoryPointer mPtr ) internal pure returns (uint160 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint168 at `mPtr` in memory. function readUint168( MemoryPointer mPtr ) internal pure returns (uint168 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint176 at `mPtr` in memory. function readUint176( MemoryPointer mPtr ) internal pure returns (uint176 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint184 at `mPtr` in memory. function readUint184( MemoryPointer mPtr ) internal pure returns (uint184 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint192 at `mPtr` in memory. function readUint192( MemoryPointer mPtr ) internal pure returns (uint192 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint200 at `mPtr` in memory. function readUint200( MemoryPointer mPtr ) internal pure returns (uint200 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint208 at `mPtr` in memory. function readUint208( MemoryPointer mPtr ) internal pure returns (uint208 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint216 at `mPtr` in memory. function readUint216( MemoryPointer mPtr ) internal pure returns (uint216 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint224 at `mPtr` in memory. function readUint224( MemoryPointer mPtr ) internal pure returns (uint224 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint232 at `mPtr` in memory. function readUint232( MemoryPointer mPtr ) internal pure returns (uint232 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint240 at `mPtr` in memory. function readUint240( MemoryPointer mPtr ) internal pure returns (uint240 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint248 at `mPtr` in memory. function readUint248( MemoryPointer mPtr ) internal pure returns (uint248 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint256 at `mPtr` in memory. function readUint256( MemoryPointer mPtr ) internal pure returns (uint256 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int8 at `mPtr` in memory. function readInt8(MemoryPointer mPtr) internal pure returns (int8 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int16 at `mPtr` in memory. function readInt16(MemoryPointer mPtr) internal pure returns (int16 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int24 at `mPtr` in memory. function readInt24(MemoryPointer mPtr) internal pure returns (int24 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int32 at `mPtr` in memory. function readInt32(MemoryPointer mPtr) internal pure returns (int32 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int40 at `mPtr` in memory. function readInt40(MemoryPointer mPtr) internal pure returns (int40 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int48 at `mPtr` in memory. function readInt48(MemoryPointer mPtr) internal pure returns (int48 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int56 at `mPtr` in memory. function readInt56(MemoryPointer mPtr) internal pure returns (int56 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int64 at `mPtr` in memory. function readInt64(MemoryPointer mPtr) internal pure returns (int64 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int72 at `mPtr` in memory. function readInt72(MemoryPointer mPtr) internal pure returns (int72 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int80 at `mPtr` in memory. function readInt80(MemoryPointer mPtr) internal pure returns (int80 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int88 at `mPtr` in memory. function readInt88(MemoryPointer mPtr) internal pure returns (int88 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int96 at `mPtr` in memory. function readInt96(MemoryPointer mPtr) internal pure returns (int96 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int104 at `mPtr` in memory. function readInt104( MemoryPointer mPtr ) internal pure returns (int104 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int112 at `mPtr` in memory. function readInt112( MemoryPointer mPtr ) internal pure returns (int112 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int120 at `mPtr` in memory. function readInt120( MemoryPointer mPtr ) internal pure returns (int120 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int128 at `mPtr` in memory. function readInt128( MemoryPointer mPtr ) internal pure returns (int128 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int136 at `mPtr` in memory. function readInt136( MemoryPointer mPtr ) internal pure returns (int136 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int144 at `mPtr` in memory. function readInt144( MemoryPointer mPtr ) internal pure returns (int144 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int152 at `mPtr` in memory. function readInt152( MemoryPointer mPtr ) internal pure returns (int152 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int160 at `mPtr` in memory. function readInt160( MemoryPointer mPtr ) internal pure returns (int160 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int168 at `mPtr` in memory. function readInt168( MemoryPointer mPtr ) internal pure returns (int168 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int176 at `mPtr` in memory. function readInt176( MemoryPointer mPtr ) internal pure returns (int176 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int184 at `mPtr` in memory. function readInt184( MemoryPointer mPtr ) internal pure returns (int184 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int192 at `mPtr` in memory. function readInt192( MemoryPointer mPtr ) internal pure returns (int192 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int200 at `mPtr` in memory. function readInt200( MemoryPointer mPtr ) internal pure returns (int200 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int208 at `mPtr` in memory. function readInt208( MemoryPointer mPtr ) internal pure returns (int208 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int216 at `mPtr` in memory. function readInt216( MemoryPointer mPtr ) internal pure returns (int216 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int224 at `mPtr` in memory. function readInt224( MemoryPointer mPtr ) internal pure returns (int224 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int232 at `mPtr` in memory. function readInt232( MemoryPointer mPtr ) internal pure returns (int232 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int240 at `mPtr` in memory. function readInt240( MemoryPointer mPtr ) internal pure returns (int240 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int248 at `mPtr` in memory. function readInt248( MemoryPointer mPtr ) internal pure returns (int248 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int256 at `mPtr` in memory. function readInt256( MemoryPointer mPtr ) internal pure returns (int256 value) { assembly { value := mload(mPtr) } } } library MemoryWriters { /// @dev Writes `valuePtr` to memory at `mPtr`. function write(MemoryPointer mPtr, MemoryPointer valuePtr) internal pure { assembly { mstore(mPtr, valuePtr) } } /// @dev Writes a boolean `value` to `mPtr` in memory. function write(MemoryPointer mPtr, bool value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes an address `value` to `mPtr` in memory. function write(MemoryPointer mPtr, address value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes a bytes32 `value` to `mPtr` in memory. /// Separate name to disambiguate literal write parameters. function writeBytes32(MemoryPointer mPtr, bytes32 value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes a uint256 `value` to `mPtr` in memory. function write(MemoryPointer mPtr, uint256 value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes an int256 `value` to `mPtr` in memory. /// Separate name to disambiguate literal write parameters. function writeInt(MemoryPointer mPtr, int256 value) internal pure { assembly { mstore(mPtr, value) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.7; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "remappings": [ "@openzeppelin/=lib/v1-core/lib/starport/lib/seaport/lib/openzeppelin-contracts/", "@rari-capital/solmate/=lib/v1-core/lib/starport/lib/seaport/lib/solmate/", "ds-test/=lib/v1-core/lib/starport/lib/seaport/lib/ds-test/src/", "erc4626-tests/=lib/v1-core/lib/starport/lib/seaport/lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/v1-core/lib/starport/lib/forge-std/src/", "murky/=lib/v1-core/lib/starport/lib/seaport/lib/murky/src/", "openzeppelin-contracts/=lib/v1-core/lib/starport/lib/seaport/lib/openzeppelin-contracts/", "seaport-core/=lib/v1-core/lib/starport/lib/seaport/lib/seaport-core/", "seaport-sol/=lib/v1-core/lib/starport/lib/seaport/lib/seaport-sol/", "seaport-types/=lib/v1-core/lib/starport/lib/seaport/lib/seaport-types/", "seaport/=lib/v1-core/lib/starport/lib/seaport/", "solady/=lib/v1-core/lib/starport/lib/solady/", "solarray/=lib/v1-core/lib/starport/lib/seaport/lib/solarray/src/", "solmate/=lib/v1-core/lib/starport/lib/solmate/src/", "starport-core/=lib/v1-core/lib/starport/src/", "starport-test/=lib/v1-core/lib/starport/test/", "starport/=lib/v1-core/lib/starport/src/", "v1-core/=lib/v1-core/src/", "cca/=lib/CCALib/src/", "cca-test/=lib/CCALib/test/", "create2deployer/=lib/create2deployer/", "CCALib/=lib/CCALib/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"seaport_","type":"address"},{"internalType":"contract Stargate","name":"stargate_","type":"address"},{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"CaveatDeadlineExpired","type":"error"},{"inputs":[],"name":"InvalidCaveat","type":"error"},{"inputs":[],"name":"InvalidCaveatLength","type":"error"},{"inputs":[],"name":"InvalidCaveatSigner","type":"error"},{"inputs":[],"name":"InvalidCustodian","type":"error"},{"inputs":[],"name":"InvalidFeeRakeBps","type":"error"},{"inputs":[],"name":"InvalidItemAmount","type":"error"},{"inputs":[],"name":"InvalidItemIdentifier","type":"error"},{"inputs":[],"name":"InvalidItemTokenNoCode","type":"error"},{"inputs":[],"name":"InvalidItemType","type":"error"},{"inputs":[],"name":"InvalidLoan","type":"error"},{"inputs":[],"name":"InvalidLoanState","type":"error"},{"inputs":[],"name":"InvalidPostRepayment","type":"error"},{"inputs":[],"name":"InvalidSalt","type":"error"},{"inputs":[],"name":"InvalidTransferLength","type":"error"},{"inputs":[],"name":"IsLocked","type":"error"},{"inputs":[],"name":"IsPaused","type":"error"},{"inputs":[],"name":"LoanExists","type":"error"},{"inputs":[],"name":"MalformedRefinance","type":"error"},{"inputs":[],"name":"NativeAssetsNotSupported","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotLoanCustodian","type":"error"},{"inputs":[],"name":"NotPaused","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnauthorizedAdditionalTransferIncluded","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint8","name":"approvalType","type":"uint8"}],"name":"ApprovalSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"CaveatFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"newNonce","type":"uint256"}],"name":"CaveatNonceIncremented","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"CaveatSaltInvalidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"loanId","type":"uint256"}],"name":"Close","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"feeTo","type":"address"},{"indexed":false,"internalType":"uint88","name":"defaultFeeRakeBps","type":"uint88"}],"name":"FeeDataUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint88","name":"overrideBps","type":"uint88"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"FeeOverrideUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"loanId","type":"uint256"},{"components":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"address","name":"custodian","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"issuer","type":"address"},{"internalType":"address","name":"originator","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SpentItem[]","name":"collateral","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SpentItem[]","name":"debt","type":"tuple[]"},{"components":[{"internalType":"address","name":"status","type":"address"},{"internalType":"bytes","name":"statusData","type":"bytes"},{"internalType":"address","name":"pricing","type":"address"},{"internalType":"bytes","name":"pricingData","type":"bytes"},{"internalType":"address","name":"settlement","type":"address"},{"internalType":"bytes","name":"settlementData","type":"bytes"}],"internalType":"struct Starport.Terms","name":"terms","type":"tuple"}],"indexed":false,"internalType":"struct Starport.Loan","name":"loan","type":"tuple"}],"name":"Open","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpaused","type":"event"},{"inputs":[],"name":"BPS_DENOMINATOR","outputs":[{"internalType":"uint88","name":"","type":"uint88"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CACHED_DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CAVEAT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_CUSTODIAN_CODE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP_DOMAIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INTENT_ORIGINATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOAN_CLOSED_FLAG","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOAN_OPEN_FLAG","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE_RAKE_BPS","outputs":[{"internalType":"uint88","name":"","type":"uint88"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SG","outputs":[{"internalType":"contract Stargate","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SpentItem[]","name":"items","type":"tuple[]"}],"name":"acquireTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SpentItem[]","name":"considerationPayment","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SpentItem[]","name":"carryPayment","type":"tuple[]"}],"name":"applyRefinanceConsiderationToLoan","outputs":[{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SpentItem[]","name":"newDebt","type":"tuple[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"approvals","outputs":[{"internalType":"enum Starport.ApprovalType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"caveatNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"}],"name":"closed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"defaultFeeRakeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"feeOverrides","outputs":[{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"uint88","name":"bpsOverride","type":"uint88"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"singleUse","type":"bool"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"components":[{"internalType":"address","name":"enforcer","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct CaveatEnforcer.Caveat[]","name":"caveats","type":"tuple[]"}],"name":"hashCaveatWithSaltAndNonce","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"incrementCaveatNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"invalidSalts","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"invalidateCaveatSalt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"loanState","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"}],"name":"open","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct AdditionalTransfer[]","name":"additionalTransfers","type":"tuple[]"},{"components":[{"internalType":"bool","name":"singleUse","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"components":[{"internalType":"address","name":"enforcer","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct CaveatEnforcer.Caveat[]","name":"caveats","type":"tuple[]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct CaveatEnforcer.SignedCaveats","name":"borrowerCaveat","type":"tuple"},{"components":[{"internalType":"bool","name":"singleUse","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"components":[{"internalType":"address","name":"enforcer","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct CaveatEnforcer.Caveat[]","name":"caveats","type":"tuple[]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct CaveatEnforcer.SignedCaveats","name":"lenderCaveat","type":"tuple"},{"components":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"address","name":"custodian","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"issuer","type":"address"},{"internalType":"address","name":"originator","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SpentItem[]","name":"collateral","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SpentItem[]","name":"debt","type":"tuple[]"},{"components":[{"internalType":"address","name":"status","type":"address"},{"internalType":"bytes","name":"statusData","type":"bytes"},{"internalType":"address","name":"pricing","type":"address"},{"internalType":"bytes","name":"pricingData","type":"bytes"},{"internalType":"address","name":"settlement","type":"address"},{"internalType":"bytes","name":"settlementData","type":"bytes"}],"internalType":"struct Starport.Terms","name":"terms","type":"tuple"}],"internalType":"struct Starport.Loan","name":"loan","type":"tuple"}],"name":"originate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"lender","type":"address"},{"components":[{"internalType":"bool","name":"singleUse","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"components":[{"internalType":"address","name":"enforcer","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct CaveatEnforcer.Caveat[]","name":"caveats","type":"tuple[]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct CaveatEnforcer.SignedCaveats","name":"lenderCaveat","type":"tuple"},{"components":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"address","name":"custodian","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"issuer","type":"address"},{"internalType":"address","name":"originator","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SpentItem[]","name":"collateral","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SpentItem[]","name":"debt","type":"tuple[]"},{"components":[{"internalType":"address","name":"status","type":"address"},{"internalType":"bytes","name":"statusData","type":"bytes"},{"internalType":"address","name":"pricing","type":"address"},{"internalType":"bytes","name":"pricingData","type":"bytes"},{"internalType":"address","name":"settlement","type":"address"},{"internalType":"bytes","name":"settlementData","type":"bytes"}],"internalType":"struct Starport.Terms","name":"terms","type":"tuple"}],"internalType":"struct Starport.Loan","name":"loan","type":"tuple"},{"internalType":"bytes","name":"pricingData","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"refinance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"feeTo_","type":"address"},{"internalType":"uint88","name":"defaultFeeRakeBps_","type":"uint88"}],"name":"setFeeData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint88","name":"bpsOverride","type":"uint88"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setFeeOverride","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"},{"internalType":"enum Starport.ApprovalType","name":"approvalType","type":"uint8"}],"name":"setOriginateApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"address","name":"custodian","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"issuer","type":"address"},{"internalType":"address","name":"originator","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SpentItem[]","name":"collateral","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SpentItem[]","name":"debt","type":"tuple[]"},{"components":[{"internalType":"address","name":"status","type":"address"},{"internalType":"bytes","name":"statusData","type":"bytes"},{"internalType":"address","name":"pricing","type":"address"},{"internalType":"bytes","name":"pricingData","type":"bytes"},{"internalType":"address","name":"settlement","type":"address"},{"internalType":"bytes","name":"settlementData","type":"bytes"}],"internalType":"struct Starport.Terms","name":"terms","type":"tuple"}],"internalType":"struct Starport.Loan","name":"loan","type":"tuple"}],"name":"settle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
61010060405260016000553480156200001757600080fd5b506040516200745c3803806200745c8339810160408190526200003a91620001e6565b6001600160a01b03821660809081524660a0818152604080518082018252600881526714dd185c9c1bdc9d60c21b6020918201528151808301835260018152600360fc1b9082015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527f5b48543dc6e9aa65ae80f87e17020dad01bd4addb08e350c7fa1919aba3f49b4818401527f044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d606082015294850193909352308483018190528151808603909301835260c0909401908190528151919092012060e0526000919085906200013090620001c2565b6001600160a01b03928316815291166020820152604001604051809103906000f08015801562000164573d6000803e3d6000fd5b50803f60c08190529091506200017a8362000185565b50505050506200023a565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a35b50565b6134848062003fd883390190565b6001600160a01b0381168114620001bf57600080fd5b600080600060608486031215620001fc57600080fd5b83516200020981620001d0565b60208501519093506200021c81620001d0565b60408501519092506200022f81620001d0565b809150509250925092565b60805160a05160c05160e051613d48620002906000396000818161031301526117ab0152600081816108030152612227015260008181610680015261178401526000818161051501526111520152613d486000f3fe6080604052600436106102675760003560e01c80637fea746611610144578063aa9d881c116100b6578063ec328eb51161007a578063ec328eb51461083b578063f04e283e1461086f578063f2fde38b14610882578063f698da2514610895578063fee81cf4146108aa578063ffa1ad74146108dd57600080fd5b8063aa9d881c1461073e578063b3b588aa1461079d578063c66f5775146107bd578063cf986b7c146107f1578063e1a452181461082557600080fd5b80638da5cb5b116101085780638da5cb5b1461060757806392d945931461062057806396a816a51461064e5780639a8a05921461066e578063a32ce11e146106a2578063a3f4df7e146106ea57600080fd5b80637fea74661461055757806381679fde146105775780638456cb59146105b2578063891569aa146105c75780638990a835146105e757600080fd5b80635c959b62116101dd578063715018a6116101a1578063715018a6146104a4578063734c4b9d146104ac578063739fe82c146104d957806373f0cdf4146104ee57806375aaa8ce1461050357806377d0c2321461053757600080fd5b80635c959b62146103e95780635c975abb146104275780635e6c2d961461043f5780636613a0c114610454578063690e7c091461047457600080fd5b8063346758b91161022f578063346758b91461033f5780633f4ba83a1461035257806349b274ed146103675780634bf261611461039457806352107d30146103c157806354d1f13d146103e157600080fd5b8063017e7e581461026c57806301ad4cc5146102a9578063196b82b3146102eb5780631c2e4be8146103015780632569296214610335575b600080fd5b34801561027857600080fd5b5060015461028c906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102b557600080fd5b506102dd7fca548e3c61dde62b5b4affcc3ced753b694921f7464c457c6cda7e3b6a1ffb8c81565b6040519081526020016102a0565b3480156102f757600080fd5b506102dd60025481565b34801561030d57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b61033d61092a565b005b61033d61034d366004612eff565b610979565b34801561035e57600080fd5b5061033d610bce565b34801561037357600080fd5b506102dd610382366004612fdf565b60076020526000908152604090205481565b3480156103a057600080fd5b506102dd6103af366004612ff8565b60066020526000908152604090205481565b3480156103cd57600080fd5b5061033d6103dc36600461301c565b610c1f565b61033d610c61565b3480156103f557600080fd5b50610417610404366004612fdf565b6000908152600760205260409020541590565b60405190151581526020016102a0565b34801561043357600080fd5b50600054600314610417565b34801561044b57600080fd5b5061033d610c9d565b34801561046057600080fd5b506102dd61046f36600461305e565b610cfe565b34801561048057600080fd5b5061041761048f366004612fdf565b60009081526007602052604090205460011490565b61033d610ed5565b3480156104b857600080fd5b506104cc6104c736600461310a565b610ee9565b6040516102a091906131cf565b3480156104e557600080fd5b506102dd600181565b3480156104fa57600080fd5b506102dd600081565b34801561050f57600080fd5b5061028c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561054357600080fd5b5061033d610552366004613218565b61112f565b34801561056357600080fd5b5061033d610572366004613263565b6111c7565b34801561058357600080fd5b50610417610592366004613298565b600560209081526000928352604080842090915290825290205460ff1681565b3480156105be57600080fd5b5061033d611267565b3480156105d357600080fd5b5061033d6105e23660046132c4565b6112b7565b3480156105f357600080fd5b5061033d61060236600461330d565b6113a1565b34801561061357600080fd5b50638b78c6d8195461028c565b34801561062c57600080fd5b506106366101f481565b6040516001600160581b0390911681526020016102a0565b34801561065a57600080fd5b5061033d610669366004613392565b61143d565b34801561067a57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106ae57600080fd5b506106dd6106bd36600461345d565b600460209081526000928352604080842090915290825290205460ff1681565b6040516102a0919061348b565b3480156106f657600080fd5b5060408051808201909152600881526714dd185c9c1bdc9d60c21b6020909101526102dd7f5b48543dc6e9aa65ae80f87e17020dad01bd4addb08e350c7fa1919aba3f49b481565b34801561074a57600080fd5b5061077e610759366004612ff8565b60036020526000908152604090205460ff81169061010090046001600160581b031682565b6040805192151583526001600160581b039091166020830152016102a0565b3480156107a957600080fd5b5061033d6107b8366004612fdf565b6116d9565b3480156107c957600080fd5b506102dd7f8c882a4ce21596ccd46e07399fdcb28818ae4274d3988aa064c98c0b99f505d181565b3480156107fd57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083157600080fd5b5061063661271081565b34801561084757600080fd5b506102dd7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b61033d61087d366004612ff8565b61171b565b61033d610890366004612ff8565b611758565b3480156108a157600080fd5b506102dd61177f565b3480156108b657600080fd5b506102dd6108c5366004612ff8565b63389a75e1600c908152600091909152602090205490565b3480156108e957600080fd5b506040805180820190915260018152600360fc1b6020909101526102dd7f044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d81565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b600160005411156109ab576002600054111561099d57631309a5636000526004601cfd5b63caa30f556000526004601cfd5b6002600055604081015160608201516001546001600160a01b039081169083163314801590610a12575060016001600160a01b038416600090815260046020908152604080832033845290915290205460ff166002811115610a0f57610a0f61316d565b14155b15610a7557610a7586848a8a808060200260200160405190810160405280939291908181526020016000905b82821015610a6a57610a5b60c083028601368190038101906134a5565b81526020019060010190610a3e565b50505050508761189d565b336001600160a01b03831614801590610ac6575060026001600160a01b038316600090815260046020908152604080832033845290915290205460ff166002811115610ac357610ac361316d565b14155b15610b1e57610b1e85838a8a808060200260200160405190810160405280939291908181526020016000905b82821015610a6a57610b0f60c083028601368190038101906134a5565b81526020019060010190610af2565b610b338460a001518486602001516001611b4e565b6001600160a01b038116610b5757610b528460c0015183856000611b4e565b610b90565b600080610b678660c00151611bcc565b8151919350915015610b8057610b808285856000611b4e565b610b8d8185876000611b4e565b50505b8615610bad57610ba38383338b8b611e55565b610bad8888611f07565b610bb684612186565b610bbf8461221e565b50505060016000555050505050565b610bd66122ec565b60036000541015610bef57636cd602016000526004601cfd5b600160009081556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d169339190a1565b80602001516001600160a01b0316336001600160a01b031614610c5557604051631e0707a560e11b815260040160405180910390fd5b610c5e81612307565b50565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b33600081815260066020908152604091829020805460001943014060801c01600101908190558251938452908301819052917fe8e5dfdf538b2dfce2d1f2dff7bc7ec9c962a7ffa5249ae7a3673468b72d067e91015b60405180910390a150565b600080826001600160401b03811115610d1957610d19612b2b565b604051908082528060200260200182016040528015610d42578160200160208202803683370190505b50905060005b83811015610daa57610d85858583818110610d6557610d6561353f565b9050602002810190610d779190613555565b610d8090613575565b61236d565b828281518110610d9757610d9761353f565b6020908102919091010152600101610d48565b601960f81b600160f81b610dbc61177f565b7fca548e3c61dde62b5b4affcc3ced753b694921f7464c457c6cda7e3b6a1ffb8c8c600660008f6001600160a01b03166001600160a01b03168152602001908152602001600020548d8d8d8a604051602001610e1891906135ea565b60408051601f198184030181528282528051602091820120908301989098526001600160a01b03909616958101959095526060850193909352901515608084015260a083015260c082015260e08101919091526101000160408051808303601f190181529082905280516020918201206001600160f81b0319958616918301919091529290931660218401526022830152604282015260620160405160208183030381529060405280519060200120925050509695505050505050565b610edd6122ec565b610ee760006123e6565b565b6060825160001480610f085750815115801590610f0857508151835114155b15610f265760405163f966b6e560e01b815260040160405180910390fd5b8151156110975782516001600160401b03811115610f4657610f46612b2b565b604051908082528060200260200182016040528015610f7f57816020015b610f6c612ae1565b815260200190600190039081610f645790505b50905060005b835181101561109157838181518110610fa057610fa061353f565b6020026020010151828281518110610fba57610fba61353f565b6020026020010181905250828181518110610fd757610fd761353f565b602002602001015160600151828281518110610ff557610ff561353f565b602002602001015160600181815161100d9190613636565b90525060028282815181106110245761102461353f565b60200260200101516000015160058111156110415761104161316d565b14801561106b5750600182828151811061105d5761105d61353f565b602002602001015160600151115b156110895760405163f966b6e560e01b815260040160405180910390fd5b600101610f85565b50611129565b60005b83518110156111245760028482815181106110b7576110b761353f565b60200260200101516000015160058111156110d4576110d461316d565b1480156110fe575060018482815181106110f0576110f061353f565b602002602001015160600151115b1561111c5760405163f966b6e560e01b815260040160405180910390fd5b60010161109a565b839150505b92915050565b60405163fa54416160e01b8152336004820152610c5e9082906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fa544161906024016020604051808303816000875af115801561119b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111bf9190613649565b336000611b4e565b6111cf6122ec565b6101f46001600160581b03821611156111fb57604051631afb16b160e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0384169081179091556001600160581b03821660028190556040805192835260208301919091527f2f940c22d2e09b994ffac2c4003c65249df0867e81c557a592b93f29e707925291015b60405180910390a15050565b61126f6122ec565b6002600054036112875763caa30f556000526004601cfd5b600360009081556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e7529190a1565b6112bf6122ec565b6101f46001600160581b03831611156112eb57604051631afb16b160e01b815260040160405180910390fd5b6040805180820182528215158082526001600160581b0385811660208085018281526001600160a01b038a166000818152600384528890209651875492516bffffffffffffffffffffffff199093169015156bffffffffffffffffffffff001916176101009290951691909102939093179094558451918252928101929092528183015290517f045231260c7d7b00ecfca40c14a8a9bc72cc0283fdd21ba2447209a696947b9f916060908290030190a1505050565b3360009081526004602090815260408083206001600160a01b03861684529091529020805482919060ff191660018360028111156113e1576113e161316d565b02179055506001600160a01b038216337fd59af26d5a1428c5bb1e4be35c39ecaedebd34020a46fae9b3672b82bd76fd9a8360028111156114245761142461316d565b60405160ff909116815260200160405180910390a35050565b60016000541115611461576002600054111561099d57631309a5636000526004601cfd5b600260005584514290036114885760405163045f33d160e01b815260040160405180910390fd5b60e0850151516040516303c2063b60e31b81526001600160a01b0390911690631e1031d8906114bf9088908690869060040161384a565b602060405180830381865afa1580156114dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611500919061387a565b61151d5760405163046c4b6360e51b815260040160405180910390fd5b60008060008760e00151604001516001600160a01b031663fdc1aa40898989336040518563ffffffff1660e01b815260040161155c9493929190613897565b600060405180830381865afa158015611579573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115a1919081019061397c565b9250925092506115b088612307565b6115ba8833612424565b6115cb838b8a606001516000611b4e565b8151156115e3576115e3828b8a608001516000611b4e565b6115ed8383610ee9565b60c0890152604080516020601f8901819004810282018101909252878152908890889081908401838280828437600092018290525060e08d01516060908101959095526001600160a01b038f16948d0185905260808d018190528c525050503314801590611693575060026001600160a01b038b16600090815260046020908152604080832033845290915290205460ff1660028111156116905761169061316d565b14155b156116a4576116a4898b838b61189d565b8051156116bf576116b68a33836124cb565b6116bf81612554565b6116c888612186565b505050600160005550505050505050565b6116e560053383612705565b60408051338152602081018390527ff6477e1235adf3e2d7737f3b3eb64d5faf363d83c5d0fb6659cee58d22d22d999101610cf3565b6117236122ec565b63389a75e1600c52806000526020600c20805442111561174b57636f5e88186000526004601cfd5b60009055610c5e816123e6565b6117606122ec565b8060601b61177657637448fbae6000526004601cfd5b610c5e816123e6565b6000467f0000000000000000000000000000000000000000000000000000000000000000036117cd57507f000000000000000000000000000000000000000000000000000000000000000090565b50604080518082018252600881526714dd185c9c1bdc9d60c21b6020918201528151808301835260018152600360fc1b9082015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527f5b48543dc6e9aa65ae80f87e17020dad01bd4addb08e350c7fa1919aba3f49b4818401527f044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d60608201524660808201523060a0808301919091528351808303909101815260c0909101909252815191012090565b60006118c7846118b06020880188613ac8565b6040880135602089013561046f60608b018b613ae5565b90506118d66020860186613ac8565b1561193b576118eb6005856040880135612705565b604080516001600160a01b038616815260208101839052868201358183015290517f1e502dcf22f55b757dddae095b92594a293eaa1d06eb2e8a1a58648fb82bd1789181900360600190a1611983565b6001600160a01b038416600090815260056020908152604080832088820135845290915290205460ff1615611983576040516381e69d9b60e01b815260040160405180910390fd5b84602001354211156119a857604051636ca2589d60e11b815260040160405180910390fd5b6119bf84826119ba6080890189613b2e565b61273f565b6119dc57604051630a454ba960e41b815260040160405180910390fd5b6119e96060860186613ae5565b9050600003611a0b576040516391289d0b60e01b815260040160405180910390fd5b60005b611a1b6060870187613ae5565b9050811015611b4657637c2e14bb60e01b611a396060880188613ae5565b83818110611a4957611a4961353f565b9050602002810190611a5b9190613555565b611a69906020810190612ff8565b6001600160a01b0316637c2e14bb8686611a8660608c018c613ae5565b87818110611a9657611a9661353f565b9050602002810190611aa89190613555565b611ab6906020810190613b2e565b6040518563ffffffff1660e01b8152600401611ad59493929190613b74565b602060405180830381865afa158015611af2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b169190613c2a565b6001600160e01b03191614611b3e57604051635575a04960e11b815260040160405180910390fd5b600101611a0e565b505050505050565b835115611bad5760005b8451811015611ba7576000858281518110611b7557611b7561353f565b60200260200101519050611b9e8160000151826020015183604001518460600151898989612839565b50600101611b58565b50611bc6565b6040516312ae6b4360e11b815260040160405180910390fd5b50505050565b60608082516001600160401b03811115611be857611be8612b2b565b604051908082528060200260200182016040528015611c2157816020015b611c0e612ae1565b815260200190600190039081611c065790505b50915082516001600160401b03811115611c3d57611c3d612b2b565b604051908082528060200260200182016040528015611c7657816020015b611c63612ae1565b815260200190600190039081611c5b5790505b506002549091506000805b8551811015611e4a57600080878381518110611c9f57611c9f61353f565b6020026020010151905060016005811115611cbc57611cbc61316d565b81516005811115611ccf57611ccf61316d565b03611dcd576020818101516001600160a01b0316600090815260038252604080822081518083019092525460ff81161515825261010090046001600160581b0316928101929092528851899087908110611d2b57611d2b61353f565b60200260200101519050600081604001818152505060008260000151611d515787611d60565b82602001516001600160581b03165b6060850151909150611d759082612710612a2d565b94508415611dc957606082018590526020808501516001600160a01b031690830152835182906005811115611dac57611dac61316d565b90816005811115611dbf57611dbf61316d565b9052506001909601955b5050505b604051806080016040528082600001516005811115611dee57611dee61316d565b815260200182602001516001600160a01b0316815260200182604001518152602001838360600151611e209190613c54565b815250868481518110611e3557611e3561353f565b60209081029190910101525050600101611c81565b508084525050915091565b60005b81811015611b46576000838383818110611e7457611e7461353f565b905060c002016040016020810190611e8c9190612ff8565b9050866001600160a01b0316816001600160a01b031614158015611ec25750856001600160a01b0316816001600160a01b031614155b8015611ee05750846001600160a01b0316816001600160a01b031614155b15611efe576040516379443ef360e01b815260040160405180910390fd5b50600101611e58565b60005b818110156121815736838383818110611f2557611f2561353f565b905060c002019050806020016020810190611f409190612ff8565b6001600160a01b03163b600003611f6a57604051638aea498d60e01b815260040160405180910390fd5b6001611f796020830183613c67565b6005811115611f8a57611f8a61316d565b03611fdb5760a081013515611fd657611fd6611fac6040830160208401612ff8565b611fbc6060840160408501612ff8565b611fcc6080850160608601612ff8565b8460a00135612a5c565b612178565b6002611fea6020830183613c67565b6005811115611ffb57611ffb61316d565b036120ae576120106040820160208301612ff8565b6001600160a01b03166323b872dd61202e6060840160408501612ff8565b61203e6080850160608601612ff8565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152608084013560448201526064015b600060405180830381600087803b15801561209157600080fd5b505af11580156120a5573d6000803e3d6000fd5b50505050612178565b60038484848181106120c2576120c261353f565b6120d892602060c0909202019081019150613c67565b60058111156120e9576120e961316d565b0361215f5760a081013515611fd6576121086040820160208301612ff8565b6001600160a01b031663f242432a6121266060840160408501612ff8565b6121366080850160608601612ff8565b84608001358560a001356040518563ffffffff1660e01b81526004016120779493929190613c84565b604051632544fd1560e21b815260040160405180910390fd5b50600101611f0a565b505050565b42815260808101516001600160a01b03166121a157336121a7565b80608001515b6001600160a01b0316608082015260006121c082612ab0565b905080600052600760205260406000208054156121e85763053b15ff60e21b60005260046000fd5b60018155507f57cb72d73c48fadf55428537f6c9efbe080ae111339b0c5af42d9027ed20ba17818360405161125b929190613cbc565b6020810151803f7f000000000000000000000000000000000000000000000000000000000000000081148015906122ce5750604051635bdaa8a360e11b808252906001600160a01b0384169063b7b551469061227e908790600401613cd5565b6020604051808303816000875af115801561229d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c19190613c2a565b6001600160e01b03191614155b156121815760405163a28b124760e01b815260040160405180910390fd5b638b78c6d819543314610ee7576382b429006000526004601cfd5b600061231282612ab0565b9050806000526007602052604060002080546123395763045f33d160e01b60005260046000fd5b600090556040518181527fbf67515a38ee520223d32c1266d52101c30d936ed1f3e436c8caeb0a43cb06bf9060200161125b565b80516020808301518051908201206040516000936123c9937f8c882a4ce21596ccd46e07399fdcb28818ae4274d3988aa064c98c0b99f505d1939192019283526001600160a01b03919091166020830152604082015260600190565b604051602081830303815290604052805190602001209050919050565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b60e0820151608001516040516340e5f59f60e01b808252916001600160a01b0316906340e5f59f9061245c9086908690600401613ce8565b6020604051808303816000875af115801561247b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249f9190613c2a565b6001600160e01b031916146124c75760405163099c352b60e01b815260040160405180910390fd5b5050565b60005b8151811015611bc65760008282815181106124eb576124eb61353f565b6020026020010151604001519050846001600160a01b0316816001600160a01b03161415801561252d5750836001600160a01b0316816001600160a01b031614155b1561254b576040516379443ef360e01b815260040160405180910390fd5b506001016124ce565b60005b81518110156124c75760008282815181106125745761257461353f565b6020026020010151905080602001516001600160a01b03163b6000036125ad57604051638aea498d60e01b815260040160405180910390fd5b6001815160058111156125c2576125c261316d565b036125f25760a0810151156125ed576125ed8160200151826040015183606001518460a00151612a5c565b6126fc565b6002815160058111156126075761260761316d565b036126925760208101516040808301516060840151608085015192516323b872dd60e01b81526001600160a01b03928316600482015290821660248201526044810192909252909116906323b872dd906064015b600060405180830381600087803b15801561267557600080fd5b505af1158015612689573d6000803e3d6000fd5b505050506126fc565b6003815160058111156126a7576126a761316d565b0361215f5760a0810151156125ed5780602001516001600160a01b031663f242432a8260400151836060015184608001518560a001516040518563ffffffff1660e01b815260040161265b9493929190613c84565b50600101612557565b81600052826020526040600020602052806000526040600020805415612736576381e69d9b60e01b60005260046000fd5b60019055505050565b6001600160a01b0390931692600084156128315760405184600052604083036127aa5760208481013560ff81901c601b01825285356040526001600160ff1b0316606052600160806000825afa805187183d15176127a857506000606052604052506001612831565b505b604183036127ed57604084013560001a602052604084604037602060016080600060015afa805187183d15176127eb57506000606052604052506001612831565b505b600060605280604052631626ba7e60e01b80825285600483015260248201604081528460448401528486606485013760208160648701858b5afa9051909114169150505b949350505050565b856001600160a01b03163b60000361286457604051638aea498d60e01b815260040160405180910390fd5b60018760058111156128785761287861316d565b036128e25760008511801561288a5750805b156128a857604051630a8afd7360e41b815260040160405180910390fd5b831580156128b35750805b156128d157604051632d4c301360e11b815260040160405180910390fd5b6128dd86848487612a5c565b612a24565b60028760058111156128f6576128f661316d565b0361299757836001141580156129095750805b1561292757604051632d4c301360e11b815260040160405180910390fd5b6040516323b872dd60e01b81526001600160a01b0384811660048301528381166024830152604482018790528716906323b872dd906064015b600060405180830381600087803b15801561297a57600080fd5b505af115801561298e573d6000803e3d6000fd5b50505050612a24565b60038760058111156129ab576129ab61316d565b03612a0b57831580156129bb5750805b156129d957604051632d4c301360e11b815260040160405180910390fd5b604051637921219560e11b81526001600160a01b0387169063f242432a9061296090869086908a908a90600401613c84565b604051631e4cbc7f60e21b815260040160405180910390fd5b50505050505050565b6000826000190484118302158202612a4d5763ad251c276000526004601cfd5b50910281810615159190040190565b60405181606052826040528360601b602c526323b872dd60601b600c52602060006064601c6000895af13d156001600051141716612aa257637939f4246000526004601cfd5b600060605260405250505050565b600081604051602001612ac39190613cd5565b60408051601f19818403018152919052805160209091012092915050565b6040805160808101909152806000815260200160006001600160a01b0316815260200160008152602001600081525090565b600060a08284031215612b2557600080fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715612b6357612b63612b2b565b60405290565b60405160c081016001600160401b0381118282101715612b6357612b63612b2b565b60405161010081016001600160401b0381118282101715612b6357612b63612b2b565b604051601f8201601f191681016001600160401b0381118282101715612bd657612bd6612b2b565b604052919050565b6001600160a01b0381168114610c5e57600080fd5b8035612bfe81612bde565b919050565b60006001600160401b03821115612c1c57612c1c612b2b565b5060051b60200190565b60068110610c5e57600080fd5b600082601f830112612c4457600080fd5b81356020612c59612c5483612c03565b612bae565b82815260079290921b84018101918181019086841115612c7857600080fd5b8286015b84811015612cdd5760808189031215612c955760008081fd5b612c9d612b41565b8135612ca881612c26565b815281850135612cb781612bde565b818601526040828101359082015260608083013590820152835291830191608001612c7c565b509695505050505050565b600082601f830112612cf957600080fd5b81356001600160401b03811115612d1257612d12612b2b565b612d25601f8201601f1916602001612bae565b818152846020838601011115612d3a57600080fd5b816020850160208301376000918101602001919091529392505050565b600060c08284031215612d6957600080fd5b612d71612b69565b9050612d7c82612bf3565b815260208201356001600160401b0380821115612d9857600080fd5b612da485838601612ce8565b6020840152612db560408501612bf3565b60408401526060840135915080821115612dce57600080fd5b612dda85838601612ce8565b6060840152612deb60808501612bf3565b608084015260a0840135915080821115612e0457600080fd5b50612e1184828501612ce8565b60a08301525092915050565b60006101008284031215612e3057600080fd5b612e38612b8b565b905081358152612e4a60208301612bf3565b6020820152612e5b60408301612bf3565b6040820152612e6c60608301612bf3565b6060820152612e7d60808301612bf3565b608082015260a08201356001600160401b0380821115612e9c57600080fd5b612ea885838601612c33565b60a084015260c0840135915080821115612ec157600080fd5b612ecd85838601612c33565b60c084015260e0840135915080821115612ee657600080fd5b50612ef384828501612d57565b60e08301525092915050565b600080600080600060808688031215612f1757600080fd5b85356001600160401b0380821115612f2e57600080fd5b818801915088601f830112612f4257600080fd5b813581811115612f5157600080fd5b89602060c083028501011115612f6657600080fd5b602092830197509550908701359080821115612f8157600080fd5b612f8d89838a01612b13565b94506040880135915080821115612fa357600080fd5b612faf89838a01612b13565b93506060880135915080821115612fc557600080fd5b50612fd288828901612e1d565b9150509295509295909350565b600060208284031215612ff157600080fd5b5035919050565b60006020828403121561300a57600080fd5b813561301581612bde565b9392505050565b60006020828403121561302e57600080fd5b81356001600160401b0381111561304457600080fd5b61283184828501612e1d565b8015158114610c5e57600080fd5b60008060008060008060a0878903121561307757600080fd5b863561308281612bde565b9550602087013561309281613050565b9450604087013593506060870135925060808701356001600160401b03808211156130bc57600080fd5b818901915089601f8301126130d057600080fd5b8135818111156130df57600080fd5b8a60208260051b85010111156130f457600080fd5b6020830194508093505050509295509295509295565b6000806040838503121561311d57600080fd5b82356001600160401b038082111561313457600080fd5b61314086838701612c33565b9350602085013591508082111561315657600080fd5b5061316385828601612c33565b9150509250929050565b634e487b7160e01b600052602160045260246000fd5b600681106131935761319361316d565b9052565b6131a2828251613183565b6020818101516001600160a01b031690830152604080820151908301526060908101519082015260800190565b6020808252825182820181905260009190848201906040850190845b8181101561320c576131fe838551613197565b9385019392506001016131eb565b50909695505050505050565b60006020828403121561322a57600080fd5b81356001600160401b0381111561324057600080fd5b61283184828501612c33565b80356001600160581b0381168114612bfe57600080fd5b6000806040838503121561327657600080fd5b823561328181612bde565b915061328f6020840161324c565b90509250929050565b600080604083850312156132ab57600080fd5b82356132b681612bde565b946020939093013593505050565b6000806000606084860312156132d957600080fd5b83356132e481612bde565b92506132f26020850161324c565b9150604084013561330281613050565b809150509250925092565b6000806040838503121561332057600080fd5b823561332b81612bde565b915060208301356003811061333f57600080fd5b809150509250929050565b60008083601f84011261335c57600080fd5b5081356001600160401b0381111561337357600080fd5b60208301915083602082850101111561338b57600080fd5b9250929050565b600080600080600080600060a0888a0312156133ad57600080fd5b87356133b881612bde565b965060208801356001600160401b03808211156133d457600080fd5b6133e08b838c01612b13565b975060408a01359150808211156133f657600080fd5b6134028b838c01612e1d565b965060608a013591508082111561341857600080fd5b6134248b838c0161334a565b909650945060808a013591508082111561343d57600080fd5b5061344a8a828b0161334a565b989b979a50959850939692959293505050565b6000806040838503121561347057600080fd5b823561347b81612bde565b9150602083013561333f81612bde565b602081016003831061349f5761349f61316d565b91905290565b600060c082840312156134b757600080fd5b60405160c081018181106001600160401b03821117156134d9576134d9612b2b565b60405282356134e781612c26565b815260208301356134f781612bde565b6020820152604083013561350a81612bde565b6040820152606083013561351d81612bde565b60608201526080838101359082015260a0928301359281019290925250919050565b634e487b7160e01b600052603260045260246000fd5b60008235603e1983360301811261356b57600080fd5b9190910192915050565b60006040823603121561358757600080fd5b604051604081016001600160401b0382821081831117156135aa576135aa612b2b565b81604052843591506135bb82612bde565b908252602084013590808211156135d157600080fd5b506135de36828601612ce8565b60208301525092915050565b815160009082906020808601845b83811015613614578151855293820193908201906001016135f8565b50929695505050505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561112957611129613620565b60006020828403121561365b57600080fd5b815161301581612bde565b600081518084526020808501945080840160005b8381101561369b5761368d878351613197565b96509082019060010161367a565b509495945050505050565b6000815180845260005b818110156136cc576020818501810151868301820152016136b0565b506000602082860101526020601f19601f83011685010191505092915050565b600060018060a01b03808351168452602083015160c0602086015261371460c08601826136a6565b90508160408501511660408601526060840151858203606087015261373982826136a6565b91505081608085015116608086015260a0840151915084810360a086015261376181836136a6565b95945050505050565b60006101008251845260018060a01b036020840151166020850152604083015161379f60408601826001600160a01b03169052565b5060608301516137ba60608601826001600160a01b03169052565b5060808301516137d560808601826001600160a01b03169052565b5060a08301518160a08601526137ed82860182613666565b91505060c083015184820360c08601526138078282613666565b91505060e083015184820360e086015261376182826136ec565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60408152600061385d604083018661376a565b8281036020840152613870818587613821565b9695505050505050565b60006020828403121561388c57600080fd5b815161301581613050565b6060815260006138aa606083018761376a565b82810360208401526138bd818688613821565b91505060018060a01b038316604083015295945050505050565b600082601f8301126138e857600080fd5b815160206138f8612c5483612c03565b82815260079290921b8401810191818101908684111561391757600080fd5b8286015b84811015612cdd57608081890312156139345760008081fd5b61393c612b41565b815161394781612c26565b81528185015161395681612bde565b81860152604082810151908201526060808301519082015283529183019160800161391b565b6000806000606080858703121561399257600080fd5b84516001600160401b03808211156139a957600080fd5b6139b5888389016138d7565b95506020915081870151818111156139cc57600080fd5b6139d889828a016138d7565b955050604080880151828111156139ee57600080fd5b88019150601f82018913613a0157600080fd5b8151613a0f612c5482612c03565b81815260c0918202840185019185820191908c841115613a2e57600080fd5b948601945b83861015613ab65780868e031215613a4b5760008081fd5b613a53612b69565b8651613a5e81612c26565b815286880151613a6d81612bde565b8189015286860151613a7e81612bde565b8187015286890151613a8f81612bde565b818a01526080878101519082015260a0808801519082015283529485019491860191613a33565b50809750505050505050509250925092565b600060208284031215613ada57600080fd5b813561301581613050565b6000808335601e19843603018112613afc57600080fd5b8301803591506001600160401b03821115613b1657600080fd5b6020019150600581901b360382131561338b57600080fd5b6000808335601e19843603018112613b4557600080fd5b8301803591506001600160401b03821115613b5f57600080fd5b60200191503681900382131561338b57600080fd5b6060808252855182820181905260009190608090818501906020808b01865b83811015613bf4578151613ba8868251613183565b808401516001600160a01b0390811687860152604080830151821690880152888201511688870152868101518787015260a0908101519086015260c09094019390820190600101613b93565b50508683039087015250613c08818961376a565b925050508281036040840152613c1f818587613821565b979650505050505050565b600060208284031215613c3c57600080fd5b81516001600160e01b03198116811461301557600080fd5b8181038181111561112957611129613620565b600060208284031215613c7957600080fd5b813561301581612c26565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b828152604060208201526000612831604083018461376a565b602081526000613015602083018461376a565b604081526000613cfb604083018561376a565b905060018060a01b0383166020830152939250505056fea2646970667358221220e85114ad197bfdcee5b3dc1561d5552dcb933e422f7f686446265774c9b8363b64736f6c6343000811003360c06040523480156200001157600080fd5b506040516200348438038062003484833981016040819052620000349162000091565b6001600160a01b0380821660a05282166080526040517f98a7ac23945182ac62b68fbe5ba35cc0bf5c4c34b3a410ce94a4c2270282d6b590600090a15050620000d0565b6001600160a01b03811681146200008e57600080fd5b50565b60008060408385031215620000a557600080fd5b8251620000b28162000078565b6020840151909250620000c58162000078565b809150509250929050565b60805160a05161334162000143600039600081816104db0152818161083e01528181610d5b0152818161129b01528181611c5a01528181611cf901528181611d740152611df90152600081816102b1015281816108b101528181611189015281816113dd015261198301526133416000f3fe60806040526004361061014b5760003560e01c806370a08231116100b6578063b88d4fde1161006f578063b88d4fde14610413578063c87b56dd14610426578063e985e9c514610446578063f23a6e611461047c578063f4dd92ce146104a9578063f5c7bd70146104c957600080fd5b806370a082311461032157806395cc095d1461034f57806395d89b411461036f578063989197651461039a578063a22cb465146103ba578063b7b55146146103da57600080fd5b806330102efe1161010857806330102efe1461024c5780633933ab0b1461026c57806342842e0e1461028c5780634426ebd01461029f578063582d4241146102d35780636352211e1461030157600080fd5b806301ffc9a71461015057806306fdde0314610185578063081812fc146101c9578063095ea7b31461020157806323b872dd146102165780632e778efc14610229575b600080fd5b34801561015c57600080fd5b5061017061016b3660046121b7565b6104fd565b60405190151581526020015b60405180910390f35b34801561019157600080fd5b5060408051808201909152601281527129ba30b93837b93a1021bab9ba37b234b0b760711b60208201525b60405161017c919061221a565b3480156101d557600080fd5b506101e96101e436600461222d565b610560565b6040516001600160a01b03909116815260200161017c565b61021461020f366004612266565b61059f565b005b610214610224366004612292565b6105ae565b34801561023557600080fd5b5061023e6106c5565b60405161017c9291906122d3565b34801561025857600080fd5b50610214610267366004612370565b610774565b34801561027857600080fd5b506101e96102873660046127b4565b6107d7565b61021461029a366004612292565b61080c565b3480156102ab57600080fd5b506101e97f000000000000000000000000000000000000000000000000000000000000000081565b3480156102df57600080fd5b506102f36102ee36600461287c565b610839565b60405161017c9291906129dd565b34801561030d57600080fd5b506101e961031c36600461222d565b610ccb565b34801561032d57600080fd5b5061034161033c366004612a70565b610d09565b60405190815260200161017c565b34801561035b57600080fd5b5061021461036a366004612a8d565b610d44565b34801561037b57600080fd5b50604080518082019091526002815261534360f01b60208201526101bc565b3480156103a657600080fd5b506102f36103b5366004612ac1565b610d4d565b3480156103c657600080fd5b506102146103d5366004612b7b565b611126565b3480156103e657600080fd5b506103fa6103f53660046127b4565b61117c565b6040516001600160e01b0319909116815260200161017c565b610214610421366004612ba9565b6111e0565b34801561043257600080fd5b506101bc61044136600461222d565b61123b565b34801561045257600080fd5b50610170610461366004612c1b565b601c52670a5a2e7a000000006008526000526030600c205490565b34801561048857600080fd5b506103fa610497366004612c49565b63f23a6e6160e01b9695505050505050565b3480156104b557600080fd5b506103fa6104c4366004612d08565b61128e565b3480156104d557600080fd5b506101e97f000000000000000000000000000000000000000000000000000000000000000081565b60006001600160e01b0319821663da0d82f560e01b148061052e57506001600160e01b03198216631be900b160e01b145b8061055a575061055a826301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b92915050565b600081600052673ec412a9852d173d60c11b601c52602060002082018201805460601b6105955763ceea21b66000526004601cfd5b6001015492915050565b6105aa3383836112ef565b5050565b6000818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b03948516949384169381169190828614830261060c57826105fe5763ceea21b66000526004601cfd5b63a11481006000526004601cfd5b8461061f5763ea553b346000526004601cfd5b85600052816001015492508233148633141761064d576030600c205461064d57634b6e7f186000526004601cfd5b821561065b57600082600101555b85851818905550601c600c8181208054600019019055600084905220805460010163ffffffff8116610695576301336cea6000526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a45b505050565b604080516001808252818301909252606091829190816020015b6040805180820190915260008152606060208201528152602001906001900390816106df579050509050604051806040016040528060088152602001604051806020016040528060008152508152508160008151811061074157610741612e04565b602002602001018190525080604051806040016040528060058152602001644c6f616e7360d81b81525090915091509091565b6107846060830160408401612a70565b6001600160a01b0316336001600160a01b0316146107b55760405163ea8e4eb560e01b815260040160405180910390fd5b6105aa6107c86060840160408501612a70565b826107d285611390565b6112ef565b6000806107e383611487565b90506107ee816114b8565b6107fc578260400151610805565b61080581610ccb565b9392505050565b6108178383836105ae565b813b156106c0576106c0838383604051806020016040528060008152506114dc565b6060807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168a6001600160a01b03161461088e57604051633786ddc360e01b815260040160405180910390fd5b600061089c84860186612e1a565b602081015180519192509042148061094657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635c959b626108e783611487565b6040518263ffffffff1660e01b815260040161090591815260200190565b602060405180830381865afa158015610922573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109469190612ec1565b156109645760405163045f33d160e01b815260040160405180910390fd5b60e08101515160408084015190516303c2063b60e31b81526000926001600160a01b031691631e1031d89161099d918691600401613013565b602060405180830381865afa1580156109ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109de9190612ec1565b90506001835160028111156109f5576109f561293a565b1480156109ff5750805b15610b2f57610a0d826107d7565b6001600160a01b03168c6001600160a01b031614158015610a6d5750610a57610a3583611487565b6000818152673ec412a9852d173d60c11b601c52602090208101016001015490565b6001600160a01b03168c6001600160a01b031614155b15610a8b5760405163a868732160e01b815260040160405180910390fd5b8160a0015194506000808360e00151604001516001600160a01b031663d5bfbdc6856040518263ffffffff1660e01b8152600401610ac99190613038565b600060405180830381865afa158015610ae6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b0e91908101906130fb565b91509150610b26828560600151838760800151611568565b95505050610cbb565b600283516002811115610b4457610b4461293a565b148015610b4f575080155b15610ca25760e0820151608001516040516327da635360e21b81526000916001600160a01b031690639f698d4c90610b8b908690600401613038565b600060405180830381865afa158015610ba8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bd0919081019061315e565b9095509050306001600160a01b03821603610bfe5760405163797ea6d760e01b815260040160405180910390fd5b610c07856117ae565b94506001600160a01b0381161580610c305750806001600160a01b03168d6001600160a01b0316145b15610c41578260a001519550610c9c565b8260e00151608001516001600160a01b0316816001600160a01b03161480610c7e575082606001516001600160a01b0316816001600160a01b0316145b610c9c575b60405163b7048cd360e01b815260040160405180910390fd5b50610cbb565b604051634a7f394f60e01b815260040160405180910390fd5b5050509850989650505050505050565b6000818152673ec412a9852d173d60c11b601c526020902081018101546001600160a01b031680610d045763ceea21b66000526004601cfd5b919050565b600081610d1e57638f4eb6046000526004601cfd5b673ec412a9852d173d60c11b601c528160005263ffffffff601c600c2054169050919050565b6105aa81611390565b606080336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d9957604051633786ddc360e01b815260040160405180910390fd5b6000610da784860186612e1a565b6020810151805191925090429003610dd25760405163045f33d160e01b815260040160405180910390fd5b60e08101515160408084015190516303c2063b60e31b81526000926001600160a01b031691631e1031d891610e0b918691600401613013565b602060405180830381865afa158015610e28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4c9190612ec1565b9050600183516002811115610e6357610e6361293a565b148015610e6d5750805b15610f9757610e7b826107d7565b6001600160a01b03168c6001600160a01b031614158015610eb95750610ea3610a3583611487565b6001600160a01b03168c6001600160a01b031614155b15610ed75760405163a868732160e01b815260040160405180910390fd5b8160a001519450610ee78261190a565b6000808360e00151604001516001600160a01b031663d5bfbdc6856040518263ffffffff1660e01b8152600401610f1e9190613038565b600060405180830381865afa158015610f3b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f6391908101906130fb565b91509150610f7b828560600151838760800151611568565b9550610f8684611948565b610f90848f6119e6565b5050611117565b600283516002811115610fac57610fac61293a565b148015610fb7575080155b15610ca25760e0820151608001516040516327da635360e21b81526000916001600160a01b031690639f698d4c90610ff3908690600401613038565b600060405180830381865afa158015611010573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611038919081019061315e565b9095509050306001600160a01b038216036110665760405163797ea6d760e01b815260040160405180910390fd5b61106f856117ae565b94506001600160a01b03811615806110985750806001600160a01b03168d6001600160a01b0316145b156110b2578260a0015195506110ad8361190a565b611102565b8260e00151608001516001600160a01b0316816001600160a01b031614806110ef575082606001516001600160a01b0316816001600160a01b0316145b15610c83576110ad8360a0015182611a8c565b61110b83611948565b611115838e611ac3565b505b50505097509795505050505050565b801515905081601c52670a5a2e7a0000000060085233600052806030600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146111c7576040516301af661f60e61b815260040160405180910390fd5b60405163e3dcaf1960e01b815260040160405180910390fd5b6111eb8585856105ae565b833b156112345761123485858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506114dc92505050565b5050505050565b6060611246826114b8565b6112635760405163045f33d160e01b815260040160405180910390fd5b61055a61126f83611b66565b6040518060600160405280602281526020016132ea6022913990611baa565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146112d957604051633786ddc360e01b815260040160405180910390fd5b50637a6ec96760e11b9998505050505050505050565b60001960601c828116925083811693508160005283673ec412a9852d173d60c11b17601c52602060002082018201805482169150816113365763ceea21b66000526004601cfd5b81851485151761135c57816000526030600c205461135c57634b6e7f186000526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600038a450505050565b60006113a361139e8361325c565b611487565b9050306113b66040840160208501612a70565b6001600160a01b03161415806114505750604051632e4acdb160e11b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635c959b6290602401602060405180830381865afa15801561142c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114509190612ec1565b1561146e5760405163045f33d160e01b815260040160405180910390fd5b610d046114816060840160408501612a70565b82611c05565b60008160405160200161149a9190613038565b60408051601f19818403018152919052805160209091012092915050565b6000818152673ec412a9852d173d60c11b601c52602090208101015460601b151590565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611523578060c08401826020870160045afa505b60208360a48301601c860160008a5af1611546573d15611546573d6000843e3d83fd5b508060e01b8251146115605763d1a57ed66000526004601cfd5b505050505050565b6060825185516115789190613268565b6001600160401b0381111561158f5761158f6123c1565b6040519080825280602002602001820160405280156115e857816020015b6040805160a0810182526000808252602080830182905292820181905260608201819052608082015282526000199092019101816115ad5790505b5090506000805b86518210156116c357600087838151811061160c5761160c612e04565b60200260200101516060015111156116b857600087838151811061163257611632612e04565b602002602001015190506040518060a001604052808260000151600581111561165d5761165d61293a565b815260200182602001516001600160a01b031681526020018260400151815260200182606001518152602001886001600160a01b03168152508483815181106116a8576116a8612e04565b6020908102919091010152506001015b8160010191506115ef565b8451156117a357600091505b84518210156117a35760008583815181106116ec576116ec612e04565b602002602001015160600151111561179857600085838151811061171257611712612e04565b602002602001015190506040518060a001604052808260000151600581111561173d5761173d61293a565b815260200182602001516001600160a01b031681526020018260400151815260200182606001518152602001866001600160a01b031681525084838151811061178857611788612e04565b6020908102919091010152506001015b8160010191506116cf565b825250949350505050565b6060600082516001600160401b038111156117cb576117cb6123c1565b60405190808252806020026020018201604052801561182457816020015b6040805160a0810182526000808252602080830182905292820181905260608201819052608082015282526000199092019101816117e95790505b50915060005b835181101561190257600084828151811061184757611847612e04565b60200260200101516060015111156118fa57600084828151811061186d5761186d612e04565b602002602001015190506040518060a00160405280826000015160058111156118985761189861293a565b815260200182602001516001600160a01b03168152602001826040015181526020018260600151815260200182608001516001600160a01b03168152508484815181106118e7576118e7612e04565b6020026020010181905250826001019250505b60010161182a565b508152919050565b60005b8160a00151518110156105aa576119408260a00151828151811061193357611933612e04565b6020026020010151611c1f565b60010161190d565b600061195382611487565b905061195e816114b8565b1561196c5761196c81611e20565b60405163052107d360e41b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906352107d30906119b8908590600401613038565b600060405180830381600087803b1580156119d257600080fd5b505af1158015611560573d6000803e3d6000fd5b60e0820151608001516040516340e5f59f60e01b808252916001600160a01b0316906340e5f59f90611a1e9086908690600401613289565b6020604051808303816000875af1158015611a3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a6191906132b3565b6001600160e01b031916146105aa5760405163099c352b60e01b815260040160405180910390fd5b50565b60005b82518110156106c057611abb838281518110611aad57611aad612e04565b602002602001015183611e2b565b600101611a8f565b60e0820151608001516040516309dca70360e01b808252916001600160a01b0316906309dca70390611afb9086908690600401613289565b6020604051808303816000875af1158015611b1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3e91906132b3565b6001600160e01b031916146105aa57604051630a7b5e7b60e31b815260040160405180910390fd5b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a900480611b81575050819003601f19909101908152919050565b6040518251601f19906020810182165b8581015184820152820180611bba575083518184018360208301165b8681015182820152840180611bd65750506000910183810160208101929092528352603f011660405292915050565b6105aa828260405180602001604052806000815250611f49565b600281516005811115611c3457611c3461293a565b03611cc3576020810151604080830151905163095ea7b360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482019290925291169063095ea7b3906044015b600060405180830381600087803b158015611caf57600080fd5b505af1158015611234573d6000803e3d6000fd5b600381516005811115611cd857611cd861293a565b03611d3857602081015160405163a22cb46560e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152600160248301529091169063a22cb46590604401611c95565b600181516005811115611d4d57611d4d61293a565b03611a89576020810151604051636eb1769f60e11b81523060048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015260001992169063dd62ed3e90604401602060405180830381865afa158015611dc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dea91906132d0565b14611a8957611a8981602001517f0000000000000000000000000000000000000000000000000000000000000000600019611f67565b611a89600082611fe9565b600282516005811115611e4057611e4061293a565b03611ea057602082015160408084015190516323b872dd60e01b81523060048201526001600160a01b03848116602483015260448201929092529116906323b872dd90606401600060405180830381600087803b1580156119d257600080fd5b600382516005811115611eb557611eb561293a565b03611f1c57602082015160408084015160608501519151637921219560e11b81523060048201526001600160a01b0385811660248301526044820192909252606481019290925260a06084830152600060a48301529091169063f242432a9060c4016119b8565b600182516005811115611f3157611f3161293a565b036105aa576105aa82602001518284606001516120b7565b611f5383836120f3565b823b156106c0576106c060008484846114dc565b816014528060345263095ea7b360601b60005260206000604460106000875af13d156001600051141716611fdf57600060345263095ea7b360601b600052600038604460106000875af1508060345260206000604460106000875af13d156001600051141716611fdf57633e3f8f736000526004601cfd5b6000603452505050565b6000611ff482610ccb565b90505060008181526001600160a01b03928316673ec412a9852d173d60c11b8117601c52602090912082018201805491938216918261203b5763ceea21b66000526004601cfd5b8260005281600101548086148487141786151761206a576030600c205461206a57634b6e7f186000526004601cfd5b801561207857600083600101555b5082189055601c600c208054600019019055816000827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8238a4505050565b816014528060345263a9059cbb60601b60005260206000604460106000875af13d156001600051141716611fdf576390b8ec186000526004601cfd5b6001600160a01b0390911690816121125763ea553b346000526004601cfd5b80600052673ec412a9852d173d60c11b601c5260206000208101810180548060601b156121475763c991cbb16000526004601cfd5b831790556000829052601c600c20805460010163ffffffff8116612173576301336cea6000526004601cfd5b9055808260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a45050565b6001600160e01b031981168114611a8957600080fd5b6000602082840312156121c957600080fd5b8135610805816121a1565b6000815180845260005b818110156121fa576020818501810151868301820152016121de565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061080560208301846121d4565b60006020828403121561223f57600080fd5b5035919050565b6001600160a01b0381168114611a8957600080fd5b8035610d0481612246565b6000806040838503121561227957600080fd5b823561228481612246565b946020939093013593505050565b6000806000606084860312156122a757600080fd5b83356122b281612246565b925060208401356122c281612246565b929592945050506040919091013590565b600060408083526122e6818401866121d4565b6020848203818601528186518084528284019150828160051b85010183890160005b8381101561234757868303601f19018552815180518452860151868401899052612334898501826121d4565b9587019593505090850190600101612308565b50909a9950505050505050505050565b6000610100828403121561236a57600080fd5b50919050565b6000806040838503121561238357600080fd5b82356001600160401b0381111561239957600080fd5b6123a585828601612357565b92505060208301356123b681612246565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b03811182821017156123f9576123f96123c1565b60405290565b60405160c081016001600160401b03811182821017156123f9576123f96123c1565b60405161010081016001600160401b03811182821017156123f9576123f96123c1565b604051606081016001600160401b03811182821017156123f9576123f96123c1565b60405160a081016001600160401b03811182821017156123f9576123f96123c1565b604051601f8201601f191681016001600160401b03811182821017156124b0576124b06123c1565b604052919050565b60006001600160401b038211156124d1576124d16123c1565b5060051b60200190565b60068110611a8957600080fd5b600082601f8301126124f957600080fd5b8135602061250e612509836124b8565b612488565b82815260079290921b8401810191818101908684111561252d57600080fd5b8286015b84811015612592576080818903121561254a5760008081fd5b6125526123d7565b813561255d816124db565b81528185013561256c81612246565b818601526040828101359082015260608083013590820152835291830191608001612531565b509695505050505050565b600082601f8301126125ae57600080fd5b81356001600160401b038111156125c7576125c76123c1565b6125da601f8201601f1916602001612488565b8181528460208386010111156125ef57600080fd5b816020850160208301376000918101602001919091529392505050565b600060c0828403121561261e57600080fd5b6126266123ff565b90506126318261225b565b815260208201356001600160401b038082111561264d57600080fd5b6126598583860161259d565b602084015261266a6040850161225b565b6040840152606084013591508082111561268357600080fd5b61268f8583860161259d565b60608401526126a06080850161225b565b608084015260a08401359150808211156126b957600080fd5b506126c68482850161259d565b60a08301525092915050565b600061010082840312156126e557600080fd5b6126ed612421565b9050813581526126ff6020830161225b565b60208201526127106040830161225b565b60408201526127216060830161225b565b60608201526127326080830161225b565b608082015260a08201356001600160401b038082111561275157600080fd5b61275d858386016124e8565b60a084015260c084013591508082111561277657600080fd5b612782858386016124e8565b60c084015260e084013591508082111561279b57600080fd5b506127a88482850161260c565b60e08301525092915050565b6000602082840312156127c657600080fd5b81356001600160401b038111156127dc57600080fd5b6127e8848285016126d2565b949350505050565b60008083601f84011261280257600080fd5b5081356001600160401b0381111561281957600080fd5b6020830191508360208260071b850101111561283457600080fd5b9250929050565b60008083601f84011261284d57600080fd5b5081356001600160401b0381111561286457600080fd5b60208301915083602082850101111561283457600080fd5b60008060008060008060008060a0898b03121561289857600080fd5b88356128a381612246565b975060208901356128b381612246565b965060408901356001600160401b03808211156128cf57600080fd5b6128db8c838d016127f0565b909850965060608b01359150808211156128f457600080fd5b6129008c838d016127f0565b909650945060808b013591508082111561291957600080fd5b506129268b828c0161283b565b999c989b5096995094979396929594505050565b634e487b7160e01b600052602160045260246000fd5b6006811061296e57634e487b7160e01b600052602160045260246000fd5b9052565b600081518084526020808501945080840160005b838110156129d257815161299b888251612950565b808401516001600160a01b031688850152604080820151908901526060908101519088015260809096019590820190600101612986565b509495945050505050565b600060408083526129f081840186612972565b83810360208581019190915285518083528682019282019060005b81811015612a62578451612a20848251612950565b848101516001600160a01b039081168587015287820151888601526060808301519086015260809182015116908401529383019360a090920191600101612a0b565b509098975050505050505050565b600060208284031215612a8257600080fd5b813561080581612246565b600060208284031215612a9f57600080fd5b81356001600160401b03811115612ab557600080fd5b6127e884828501612357565b60008060008060008060006080888a031215612adc57600080fd5b8735612ae781612246565b965060208801356001600160401b0380821115612b0357600080fd5b612b0f8b838c016127f0565b909850965060408a0135915080821115612b2857600080fd5b612b348b838c016127f0565b909650945060608a0135915080821115612b4d57600080fd5b50612b5a8a828b0161283b565b989b979a50959850939692959293505050565b8015158114611a8957600080fd5b60008060408385031215612b8e57600080fd5b8235612b9981612246565b915060208301356123b681612b6d565b600080600080600060808688031215612bc157600080fd5b8535612bcc81612246565b94506020860135612bdc81612246565b93506040860135925060608601356001600160401b03811115612bfe57600080fd5b612c0a8882890161283b565b969995985093965092949392505050565b60008060408385031215612c2e57600080fd5b8235612c3981612246565b915060208301356123b681612246565b60008060008060008060a08789031215612c6257600080fd5b8635612c6d81612246565b95506020870135612c7d81612246565b9450604087013593506060870135925060808701356001600160401b03811115612ca657600080fd5b612cb289828a0161283b565b979a9699509497509295939492505050565b60008083601f840112612cd657600080fd5b5081356001600160401b03811115612ced57600080fd5b6020830191508360208260051b850101111561283457600080fd5b600080600080600080600080600060a08a8c031215612d2657600080fd5b89356001600160401b0380821115612d3d57600080fd5b612d498d838e016127f0565b909b50995060208c0135915080821115612d6257600080fd5b818c0191508c601f830112612d7657600080fd5b813581811115612d8557600080fd5b8d602060a083028501011115612d9a57600080fd5b6020830199508098505060408c0135915080821115612db857600080fd5b612dc48d838e0161283b565b909750955060608c0135915080821115612ddd57600080fd5b50612dea8c828d01612cc4565b9a9d999c50979a9699959894979660800135949350505050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215612e2c57600080fd5b81356001600160401b0380821115612e4357600080fd5b9083019060608286031215612e5757600080fd5b612e5f612444565b823560038110612e6e57600080fd5b8152602083013582811115612e8257600080fd5b612e8e878286016126d2565b602083015250604083013582811115612ea657600080fd5b612eb28782860161259d565b60408301525095945050505050565b600060208284031215612ed357600080fd5b815161080581612b6d565b600060018060a01b03808351168452602083015160c06020860152612f0660c08601826121d4565b905081604085015116604086015260608401518582036060870152612f2b82826121d4565b91505081608085015116608086015260a0840151915084810360a0860152612f5381836121d4565b95945050505050565b60006101008251845260018060a01b0360208401511660208501526040830151612f9160408601826001600160a01b03169052565b506060830151612fac60608601826001600160a01b03169052565b506080830151612fc760808601826001600160a01b03169052565b5060a08301518160a0860152612fdf82860182612972565b91505060c083015184820360c0860152612ff98282612972565b91505060e083015184820360e0860152612f538282612ede565b6040815260006130266040830185612f5c565b8281036020840152612f5381856121d4565b6020815260006108056020830184612f5c565b8051610d0481612246565b600082601f83011261306757600080fd5b81516020613077612509836124b8565b82815260079290921b8401810191818101908684111561309657600080fd5b8286015b8481101561259257608081890312156130b35760008081fd5b6130bb6123d7565b81516130c6816124db565b8152818501516130d581612246565b81860152604082810151908201526060808301519082015283529183019160800161309a565b6000806040838503121561310e57600080fd5b82516001600160401b038082111561312557600080fd5b61313186838701613056565b9350602085015191508082111561314757600080fd5b5061315485828601613056565b9150509250929050565b600080604080848603121561317257600080fd5b83516001600160401b0381111561318857600080fd5b8401601f8101861361319957600080fd5b805160206131a9612509836124b8565b82815260a0928302840182019282820191908a8511156131c857600080fd5b948301945b8486101561323f5780868c0312156131e55760008081fd5b6131ed612466565b86516131f8816124db565b81528685015161320781612246565b8186015286880151888201526060808801519082015260808088015161322c81612246565b90820152835294850194918301916131cd565b50965061324f905087820161304b565b9450505050509250929050565b600061055a36836126d2565b8082018082111561055a57634e487b7160e01b600052601160045260246000fd5b60408152600061329c6040830185612f5c565b905060018060a01b03831660208301529392505050565b6000602082840312156132c557600080fd5b8151610805816121a1565b6000602082840312156132e257600080fd5b505191905056fe68747470733a2f2f617374617269612e78797a2f6d657461646174612f6c6f616e2fa2646970667358221220105c674d0c400e2faac5087ec758de2910c0807a5fb5a5133e239e09bb8c4e5264736f6c6343000811003300000000000000000000000000000000000000adc04c56bf30ac9d3c0aaf14dc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000009f23809459e3565f86d3329e7fd8309e9a58b26c
Deployed Bytecode
0x6080604052600436106102675760003560e01c80637fea746611610144578063aa9d881c116100b6578063ec328eb51161007a578063ec328eb51461083b578063f04e283e1461086f578063f2fde38b14610882578063f698da2514610895578063fee81cf4146108aa578063ffa1ad74146108dd57600080fd5b8063aa9d881c1461073e578063b3b588aa1461079d578063c66f5775146107bd578063cf986b7c146107f1578063e1a452181461082557600080fd5b80638da5cb5b116101085780638da5cb5b1461060757806392d945931461062057806396a816a51461064e5780639a8a05921461066e578063a32ce11e146106a2578063a3f4df7e146106ea57600080fd5b80637fea74661461055757806381679fde146105775780638456cb59146105b2578063891569aa146105c75780638990a835146105e757600080fd5b80635c959b62116101dd578063715018a6116101a1578063715018a6146104a4578063734c4b9d146104ac578063739fe82c146104d957806373f0cdf4146104ee57806375aaa8ce1461050357806377d0c2321461053757600080fd5b80635c959b62146103e95780635c975abb146104275780635e6c2d961461043f5780636613a0c114610454578063690e7c091461047457600080fd5b8063346758b91161022f578063346758b91461033f5780633f4ba83a1461035257806349b274ed146103675780634bf261611461039457806352107d30146103c157806354d1f13d146103e157600080fd5b8063017e7e581461026c57806301ad4cc5146102a9578063196b82b3146102eb5780631c2e4be8146103015780632569296214610335575b600080fd5b34801561027857600080fd5b5060015461028c906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102b557600080fd5b506102dd7fca548e3c61dde62b5b4affcc3ced753b694921f7464c457c6cda7e3b6a1ffb8c81565b6040519081526020016102a0565b3480156102f757600080fd5b506102dd60025481565b34801561030d57600080fd5b506102dd7fa55130c589d32fad6b7fbbd5d4d50088117b696277f9ecedc78a3cc58a9f85e581565b61033d61092a565b005b61033d61034d366004612eff565b610979565b34801561035e57600080fd5b5061033d610bce565b34801561037357600080fd5b506102dd610382366004612fdf565b60076020526000908152604090205481565b3480156103a057600080fd5b506102dd6103af366004612ff8565b60066020526000908152604090205481565b3480156103cd57600080fd5b5061033d6103dc36600461301c565b610c1f565b61033d610c61565b3480156103f557600080fd5b50610417610404366004612fdf565b6000908152600760205260409020541590565b60405190151581526020016102a0565b34801561043357600080fd5b50600054600314610417565b34801561044b57600080fd5b5061033d610c9d565b34801561046057600080fd5b506102dd61046f36600461305e565b610cfe565b34801561048057600080fd5b5061041761048f366004612fdf565b60009081526007602052604090205460011490565b61033d610ed5565b3480156104b857600080fd5b506104cc6104c736600461310a565b610ee9565b6040516102a091906131cf565b3480156104e557600080fd5b506102dd600181565b3480156104fa57600080fd5b506102dd600081565b34801561050f57600080fd5b5061028c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561054357600080fd5b5061033d610552366004613218565b61112f565b34801561056357600080fd5b5061033d610572366004613263565b6111c7565b34801561058357600080fd5b50610417610592366004613298565b600560209081526000928352604080842090915290825290205460ff1681565b3480156105be57600080fd5b5061033d611267565b3480156105d357600080fd5b5061033d6105e23660046132c4565b6112b7565b3480156105f357600080fd5b5061033d61060236600461330d565b6113a1565b34801561061357600080fd5b50638b78c6d8195461028c565b34801561062c57600080fd5b506106366101f481565b6040516001600160581b0390911681526020016102a0565b34801561065a57600080fd5b5061033d610669366004613392565b61143d565b34801561067a57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000181565b3480156106ae57600080fd5b506106dd6106bd36600461345d565b600460209081526000928352604080842090915290825290205460ff1681565b6040516102a0919061348b565b3480156106f657600080fd5b5060408051808201909152600881526714dd185c9c1bdc9d60c21b6020909101526102dd7f5b48543dc6e9aa65ae80f87e17020dad01bd4addb08e350c7fa1919aba3f49b481565b34801561074a57600080fd5b5061077e610759366004612ff8565b60036020526000908152604090205460ff81169061010090046001600160581b031682565b6040805192151583526001600160581b039091166020830152016102a0565b3480156107a957600080fd5b5061033d6107b8366004612fdf565b6116d9565b3480156107c957600080fd5b506102dd7f8c882a4ce21596ccd46e07399fdcb28818ae4274d3988aa064c98c0b99f505d181565b3480156107fd57600080fd5b506102dd7fd2b7147a7862b63eeeb1d1c609a123479d282ba6d1811a8170346a9e3ff9120481565b34801561083157600080fd5b5061063661271081565b34801561084757600080fd5b506102dd7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b61033d61087d366004612ff8565b61171b565b61033d610890366004612ff8565b611758565b3480156108a157600080fd5b506102dd61177f565b3480156108b657600080fd5b506102dd6108c5366004612ff8565b63389a75e1600c908152600091909152602090205490565b3480156108e957600080fd5b506040805180820190915260018152600360fc1b6020909101526102dd7f044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d81565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b600160005411156109ab576002600054111561099d57631309a5636000526004601cfd5b63caa30f556000526004601cfd5b6002600055604081015160608201516001546001600160a01b039081169083163314801590610a12575060016001600160a01b038416600090815260046020908152604080832033845290915290205460ff166002811115610a0f57610a0f61316d565b14155b15610a7557610a7586848a8a808060200260200160405190810160405280939291908181526020016000905b82821015610a6a57610a5b60c083028601368190038101906134a5565b81526020019060010190610a3e565b50505050508761189d565b336001600160a01b03831614801590610ac6575060026001600160a01b038316600090815260046020908152604080832033845290915290205460ff166002811115610ac357610ac361316d565b14155b15610b1e57610b1e85838a8a808060200260200160405190810160405280939291908181526020016000905b82821015610a6a57610b0f60c083028601368190038101906134a5565b81526020019060010190610af2565b610b338460a001518486602001516001611b4e565b6001600160a01b038116610b5757610b528460c0015183856000611b4e565b610b90565b600080610b678660c00151611bcc565b8151919350915015610b8057610b808285856000611b4e565b610b8d8185876000611b4e565b50505b8615610bad57610ba38383338b8b611e55565b610bad8888611f07565b610bb684612186565b610bbf8461221e565b50505060016000555050505050565b610bd66122ec565b60036000541015610bef57636cd602016000526004601cfd5b600160009081556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d169339190a1565b80602001516001600160a01b0316336001600160a01b031614610c5557604051631e0707a560e11b815260040160405180910390fd5b610c5e81612307565b50565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b33600081815260066020908152604091829020805460001943014060801c01600101908190558251938452908301819052917fe8e5dfdf538b2dfce2d1f2dff7bc7ec9c962a7ffa5249ae7a3673468b72d067e91015b60405180910390a150565b600080826001600160401b03811115610d1957610d19612b2b565b604051908082528060200260200182016040528015610d42578160200160208202803683370190505b50905060005b83811015610daa57610d85858583818110610d6557610d6561353f565b9050602002810190610d779190613555565b610d8090613575565b61236d565b828281518110610d9757610d9761353f565b6020908102919091010152600101610d48565b601960f81b600160f81b610dbc61177f565b7fca548e3c61dde62b5b4affcc3ced753b694921f7464c457c6cda7e3b6a1ffb8c8c600660008f6001600160a01b03166001600160a01b03168152602001908152602001600020548d8d8d8a604051602001610e1891906135ea565b60408051601f198184030181528282528051602091820120908301989098526001600160a01b03909616958101959095526060850193909352901515608084015260a083015260c082015260e08101919091526101000160408051808303601f190181529082905280516020918201206001600160f81b0319958616918301919091529290931660218401526022830152604282015260620160405160208183030381529060405280519060200120925050509695505050505050565b610edd6122ec565b610ee760006123e6565b565b6060825160001480610f085750815115801590610f0857508151835114155b15610f265760405163f966b6e560e01b815260040160405180910390fd5b8151156110975782516001600160401b03811115610f4657610f46612b2b565b604051908082528060200260200182016040528015610f7f57816020015b610f6c612ae1565b815260200190600190039081610f645790505b50905060005b835181101561109157838181518110610fa057610fa061353f565b6020026020010151828281518110610fba57610fba61353f565b6020026020010181905250828181518110610fd757610fd761353f565b602002602001015160600151828281518110610ff557610ff561353f565b602002602001015160600181815161100d9190613636565b90525060028282815181106110245761102461353f565b60200260200101516000015160058111156110415761104161316d565b14801561106b5750600182828151811061105d5761105d61353f565b602002602001015160600151115b156110895760405163f966b6e560e01b815260040160405180910390fd5b600101610f85565b50611129565b60005b83518110156111245760028482815181106110b7576110b761353f565b60200260200101516000015160058111156110d4576110d461316d565b1480156110fe575060018482815181106110f0576110f061353f565b602002602001015160600151115b1561111c5760405163f966b6e560e01b815260040160405180910390fd5b60010161109a565b839150505b92915050565b60405163fa54416160e01b8152336004820152610c5e9082906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fa544161906024016020604051808303816000875af115801561119b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111bf9190613649565b336000611b4e565b6111cf6122ec565b6101f46001600160581b03821611156111fb57604051631afb16b160e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0384169081179091556001600160581b03821660028190556040805192835260208301919091527f2f940c22d2e09b994ffac2c4003c65249df0867e81c557a592b93f29e707925291015b60405180910390a15050565b61126f6122ec565b6002600054036112875763caa30f556000526004601cfd5b600360009081556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e7529190a1565b6112bf6122ec565b6101f46001600160581b03831611156112eb57604051631afb16b160e01b815260040160405180910390fd5b6040805180820182528215158082526001600160581b0385811660208085018281526001600160a01b038a166000818152600384528890209651875492516bffffffffffffffffffffffff199093169015156bffffffffffffffffffffff001916176101009290951691909102939093179094558451918252928101929092528183015290517f045231260c7d7b00ecfca40c14a8a9bc72cc0283fdd21ba2447209a696947b9f916060908290030190a1505050565b3360009081526004602090815260408083206001600160a01b03861684529091529020805482919060ff191660018360028111156113e1576113e161316d565b02179055506001600160a01b038216337fd59af26d5a1428c5bb1e4be35c39ecaedebd34020a46fae9b3672b82bd76fd9a8360028111156114245761142461316d565b60405160ff909116815260200160405180910390a35050565b60016000541115611461576002600054111561099d57631309a5636000526004601cfd5b600260005584514290036114885760405163045f33d160e01b815260040160405180910390fd5b60e0850151516040516303c2063b60e31b81526001600160a01b0390911690631e1031d8906114bf9088908690869060040161384a565b602060405180830381865afa1580156114dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611500919061387a565b61151d5760405163046c4b6360e51b815260040160405180910390fd5b60008060008760e00151604001516001600160a01b031663fdc1aa40898989336040518563ffffffff1660e01b815260040161155c9493929190613897565b600060405180830381865afa158015611579573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115a1919081019061397c565b9250925092506115b088612307565b6115ba8833612424565b6115cb838b8a606001516000611b4e565b8151156115e3576115e3828b8a608001516000611b4e565b6115ed8383610ee9565b60c0890152604080516020601f8901819004810282018101909252878152908890889081908401838280828437600092018290525060e08d01516060908101959095526001600160a01b038f16948d0185905260808d018190528c525050503314801590611693575060026001600160a01b038b16600090815260046020908152604080832033845290915290205460ff1660028111156116905761169061316d565b14155b156116a4576116a4898b838b61189d565b8051156116bf576116b68a33836124cb565b6116bf81612554565b6116c888612186565b505050600160005550505050505050565b6116e560053383612705565b60408051338152602081018390527ff6477e1235adf3e2d7737f3b3eb64d5faf363d83c5d0fb6659cee58d22d22d999101610cf3565b6117236122ec565b63389a75e1600c52806000526020600c20805442111561174b57636f5e88186000526004601cfd5b60009055610c5e816123e6565b6117606122ec565b8060601b61177657637448fbae6000526004601cfd5b610c5e816123e6565b6000467f0000000000000000000000000000000000000000000000000000000000000001036117cd57507fa55130c589d32fad6b7fbbd5d4d50088117b696277f9ecedc78a3cc58a9f85e590565b50604080518082018252600881526714dd185c9c1bdc9d60c21b6020918201528151808301835260018152600360fc1b9082015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527f5b48543dc6e9aa65ae80f87e17020dad01bd4addb08e350c7fa1919aba3f49b4818401527f044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d60608201524660808201523060a0808301919091528351808303909101815260c0909101909252815191012090565b60006118c7846118b06020880188613ac8565b6040880135602089013561046f60608b018b613ae5565b90506118d66020860186613ac8565b1561193b576118eb6005856040880135612705565b604080516001600160a01b038616815260208101839052868201358183015290517f1e502dcf22f55b757dddae095b92594a293eaa1d06eb2e8a1a58648fb82bd1789181900360600190a1611983565b6001600160a01b038416600090815260056020908152604080832088820135845290915290205460ff1615611983576040516381e69d9b60e01b815260040160405180910390fd5b84602001354211156119a857604051636ca2589d60e11b815260040160405180910390fd5b6119bf84826119ba6080890189613b2e565b61273f565b6119dc57604051630a454ba960e41b815260040160405180910390fd5b6119e96060860186613ae5565b9050600003611a0b576040516391289d0b60e01b815260040160405180910390fd5b60005b611a1b6060870187613ae5565b9050811015611b4657637c2e14bb60e01b611a396060880188613ae5565b83818110611a4957611a4961353f565b9050602002810190611a5b9190613555565b611a69906020810190612ff8565b6001600160a01b0316637c2e14bb8686611a8660608c018c613ae5565b87818110611a9657611a9661353f565b9050602002810190611aa89190613555565b611ab6906020810190613b2e565b6040518563ffffffff1660e01b8152600401611ad59493929190613b74565b602060405180830381865afa158015611af2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b169190613c2a565b6001600160e01b03191614611b3e57604051635575a04960e11b815260040160405180910390fd5b600101611a0e565b505050505050565b835115611bad5760005b8451811015611ba7576000858281518110611b7557611b7561353f565b60200260200101519050611b9e8160000151826020015183604001518460600151898989612839565b50600101611b58565b50611bc6565b6040516312ae6b4360e11b815260040160405180910390fd5b50505050565b60608082516001600160401b03811115611be857611be8612b2b565b604051908082528060200260200182016040528015611c2157816020015b611c0e612ae1565b815260200190600190039081611c065790505b50915082516001600160401b03811115611c3d57611c3d612b2b565b604051908082528060200260200182016040528015611c7657816020015b611c63612ae1565b815260200190600190039081611c5b5790505b506002549091506000805b8551811015611e4a57600080878381518110611c9f57611c9f61353f565b6020026020010151905060016005811115611cbc57611cbc61316d565b81516005811115611ccf57611ccf61316d565b03611dcd576020818101516001600160a01b0316600090815260038252604080822081518083019092525460ff81161515825261010090046001600160581b0316928101929092528851899087908110611d2b57611d2b61353f565b60200260200101519050600081604001818152505060008260000151611d515787611d60565b82602001516001600160581b03165b6060850151909150611d759082612710612a2d565b94508415611dc957606082018590526020808501516001600160a01b031690830152835182906005811115611dac57611dac61316d565b90816005811115611dbf57611dbf61316d565b9052506001909601955b5050505b604051806080016040528082600001516005811115611dee57611dee61316d565b815260200182602001516001600160a01b0316815260200182604001518152602001838360600151611e209190613c54565b815250868481518110611e3557611e3561353f565b60209081029190910101525050600101611c81565b508084525050915091565b60005b81811015611b46576000838383818110611e7457611e7461353f565b905060c002016040016020810190611e8c9190612ff8565b9050866001600160a01b0316816001600160a01b031614158015611ec25750856001600160a01b0316816001600160a01b031614155b8015611ee05750846001600160a01b0316816001600160a01b031614155b15611efe576040516379443ef360e01b815260040160405180910390fd5b50600101611e58565b60005b818110156121815736838383818110611f2557611f2561353f565b905060c002019050806020016020810190611f409190612ff8565b6001600160a01b03163b600003611f6a57604051638aea498d60e01b815260040160405180910390fd5b6001611f796020830183613c67565b6005811115611f8a57611f8a61316d565b03611fdb5760a081013515611fd657611fd6611fac6040830160208401612ff8565b611fbc6060840160408501612ff8565b611fcc6080850160608601612ff8565b8460a00135612a5c565b612178565b6002611fea6020830183613c67565b6005811115611ffb57611ffb61316d565b036120ae576120106040820160208301612ff8565b6001600160a01b03166323b872dd61202e6060840160408501612ff8565b61203e6080850160608601612ff8565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152608084013560448201526064015b600060405180830381600087803b15801561209157600080fd5b505af11580156120a5573d6000803e3d6000fd5b50505050612178565b60038484848181106120c2576120c261353f565b6120d892602060c0909202019081019150613c67565b60058111156120e9576120e961316d565b0361215f5760a081013515611fd6576121086040820160208301612ff8565b6001600160a01b031663f242432a6121266060840160408501612ff8565b6121366080850160608601612ff8565b84608001358560a001356040518563ffffffff1660e01b81526004016120779493929190613c84565b604051632544fd1560e21b815260040160405180910390fd5b50600101611f0a565b505050565b42815260808101516001600160a01b03166121a157336121a7565b80608001515b6001600160a01b0316608082015260006121c082612ab0565b905080600052600760205260406000208054156121e85763053b15ff60e21b60005260046000fd5b60018155507f57cb72d73c48fadf55428537f6c9efbe080ae111339b0c5af42d9027ed20ba17818360405161125b929190613cbc565b6020810151803f7fd2b7147a7862b63eeeb1d1c609a123479d282ba6d1811a8170346a9e3ff9120481148015906122ce5750604051635bdaa8a360e11b808252906001600160a01b0384169063b7b551469061227e908790600401613cd5565b6020604051808303816000875af115801561229d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c19190613c2a565b6001600160e01b03191614155b156121815760405163a28b124760e01b815260040160405180910390fd5b638b78c6d819543314610ee7576382b429006000526004601cfd5b600061231282612ab0565b9050806000526007602052604060002080546123395763045f33d160e01b60005260046000fd5b600090556040518181527fbf67515a38ee520223d32c1266d52101c30d936ed1f3e436c8caeb0a43cb06bf9060200161125b565b80516020808301518051908201206040516000936123c9937f8c882a4ce21596ccd46e07399fdcb28818ae4274d3988aa064c98c0b99f505d1939192019283526001600160a01b03919091166020830152604082015260600190565b604051602081830303815290604052805190602001209050919050565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b60e0820151608001516040516340e5f59f60e01b808252916001600160a01b0316906340e5f59f9061245c9086908690600401613ce8565b6020604051808303816000875af115801561247b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249f9190613c2a565b6001600160e01b031916146124c75760405163099c352b60e01b815260040160405180910390fd5b5050565b60005b8151811015611bc65760008282815181106124eb576124eb61353f565b6020026020010151604001519050846001600160a01b0316816001600160a01b03161415801561252d5750836001600160a01b0316816001600160a01b031614155b1561254b576040516379443ef360e01b815260040160405180910390fd5b506001016124ce565b60005b81518110156124c75760008282815181106125745761257461353f565b6020026020010151905080602001516001600160a01b03163b6000036125ad57604051638aea498d60e01b815260040160405180910390fd5b6001815160058111156125c2576125c261316d565b036125f25760a0810151156125ed576125ed8160200151826040015183606001518460a00151612a5c565b6126fc565b6002815160058111156126075761260761316d565b036126925760208101516040808301516060840151608085015192516323b872dd60e01b81526001600160a01b03928316600482015290821660248201526044810192909252909116906323b872dd906064015b600060405180830381600087803b15801561267557600080fd5b505af1158015612689573d6000803e3d6000fd5b505050506126fc565b6003815160058111156126a7576126a761316d565b0361215f5760a0810151156125ed5780602001516001600160a01b031663f242432a8260400151836060015184608001518560a001516040518563ffffffff1660e01b815260040161265b9493929190613c84565b50600101612557565b81600052826020526040600020602052806000526040600020805415612736576381e69d9b60e01b60005260046000fd5b60019055505050565b6001600160a01b0390931692600084156128315760405184600052604083036127aa5760208481013560ff81901c601b01825285356040526001600160ff1b0316606052600160806000825afa805187183d15176127a857506000606052604052506001612831565b505b604183036127ed57604084013560001a602052604084604037602060016080600060015afa805187183d15176127eb57506000606052604052506001612831565b505b600060605280604052631626ba7e60e01b80825285600483015260248201604081528460448401528486606485013760208160648701858b5afa9051909114169150505b949350505050565b856001600160a01b03163b60000361286457604051638aea498d60e01b815260040160405180910390fd5b60018760058111156128785761287861316d565b036128e25760008511801561288a5750805b156128a857604051630a8afd7360e41b815260040160405180910390fd5b831580156128b35750805b156128d157604051632d4c301360e11b815260040160405180910390fd5b6128dd86848487612a5c565b612a24565b60028760058111156128f6576128f661316d565b0361299757836001141580156129095750805b1561292757604051632d4c301360e11b815260040160405180910390fd5b6040516323b872dd60e01b81526001600160a01b0384811660048301528381166024830152604482018790528716906323b872dd906064015b600060405180830381600087803b15801561297a57600080fd5b505af115801561298e573d6000803e3d6000fd5b50505050612a24565b60038760058111156129ab576129ab61316d565b03612a0b57831580156129bb5750805b156129d957604051632d4c301360e11b815260040160405180910390fd5b604051637921219560e11b81526001600160a01b0387169063f242432a9061296090869086908a908a90600401613c84565b604051631e4cbc7f60e21b815260040160405180910390fd5b50505050505050565b6000826000190484118302158202612a4d5763ad251c276000526004601cfd5b50910281810615159190040190565b60405181606052826040528360601b602c526323b872dd60601b600c52602060006064601c6000895af13d156001600051141716612aa257637939f4246000526004601cfd5b600060605260405250505050565b600081604051602001612ac39190613cd5565b60408051601f19818403018152919052805160209091012092915050565b6040805160808101909152806000815260200160006001600160a01b0316815260200160008152602001600081525090565b600060a08284031215612b2557600080fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715612b6357612b63612b2b565b60405290565b60405160c081016001600160401b0381118282101715612b6357612b63612b2b565b60405161010081016001600160401b0381118282101715612b6357612b63612b2b565b604051601f8201601f191681016001600160401b0381118282101715612bd657612bd6612b2b565b604052919050565b6001600160a01b0381168114610c5e57600080fd5b8035612bfe81612bde565b919050565b60006001600160401b03821115612c1c57612c1c612b2b565b5060051b60200190565b60068110610c5e57600080fd5b600082601f830112612c4457600080fd5b81356020612c59612c5483612c03565b612bae565b82815260079290921b84018101918181019086841115612c7857600080fd5b8286015b84811015612cdd5760808189031215612c955760008081fd5b612c9d612b41565b8135612ca881612c26565b815281850135612cb781612bde565b818601526040828101359082015260608083013590820152835291830191608001612c7c565b509695505050505050565b600082601f830112612cf957600080fd5b81356001600160401b03811115612d1257612d12612b2b565b612d25601f8201601f1916602001612bae565b818152846020838601011115612d3a57600080fd5b816020850160208301376000918101602001919091529392505050565b600060c08284031215612d6957600080fd5b612d71612b69565b9050612d7c82612bf3565b815260208201356001600160401b0380821115612d9857600080fd5b612da485838601612ce8565b6020840152612db560408501612bf3565b60408401526060840135915080821115612dce57600080fd5b612dda85838601612ce8565b6060840152612deb60808501612bf3565b608084015260a0840135915080821115612e0457600080fd5b50612e1184828501612ce8565b60a08301525092915050565b60006101008284031215612e3057600080fd5b612e38612b8b565b905081358152612e4a60208301612bf3565b6020820152612e5b60408301612bf3565b6040820152612e6c60608301612bf3565b6060820152612e7d60808301612bf3565b608082015260a08201356001600160401b0380821115612e9c57600080fd5b612ea885838601612c33565b60a084015260c0840135915080821115612ec157600080fd5b612ecd85838601612c33565b60c084015260e0840135915080821115612ee657600080fd5b50612ef384828501612d57565b60e08301525092915050565b600080600080600060808688031215612f1757600080fd5b85356001600160401b0380821115612f2e57600080fd5b818801915088601f830112612f4257600080fd5b813581811115612f5157600080fd5b89602060c083028501011115612f6657600080fd5b602092830197509550908701359080821115612f8157600080fd5b612f8d89838a01612b13565b94506040880135915080821115612fa357600080fd5b612faf89838a01612b13565b93506060880135915080821115612fc557600080fd5b50612fd288828901612e1d565b9150509295509295909350565b600060208284031215612ff157600080fd5b5035919050565b60006020828403121561300a57600080fd5b813561301581612bde565b9392505050565b60006020828403121561302e57600080fd5b81356001600160401b0381111561304457600080fd5b61283184828501612e1d565b8015158114610c5e57600080fd5b60008060008060008060a0878903121561307757600080fd5b863561308281612bde565b9550602087013561309281613050565b9450604087013593506060870135925060808701356001600160401b03808211156130bc57600080fd5b818901915089601f8301126130d057600080fd5b8135818111156130df57600080fd5b8a60208260051b85010111156130f457600080fd5b6020830194508093505050509295509295509295565b6000806040838503121561311d57600080fd5b82356001600160401b038082111561313457600080fd5b61314086838701612c33565b9350602085013591508082111561315657600080fd5b5061316385828601612c33565b9150509250929050565b634e487b7160e01b600052602160045260246000fd5b600681106131935761319361316d565b9052565b6131a2828251613183565b6020818101516001600160a01b031690830152604080820151908301526060908101519082015260800190565b6020808252825182820181905260009190848201906040850190845b8181101561320c576131fe838551613197565b9385019392506001016131eb565b50909695505050505050565b60006020828403121561322a57600080fd5b81356001600160401b0381111561324057600080fd5b61283184828501612c33565b80356001600160581b0381168114612bfe57600080fd5b6000806040838503121561327657600080fd5b823561328181612bde565b915061328f6020840161324c565b90509250929050565b600080604083850312156132ab57600080fd5b82356132b681612bde565b946020939093013593505050565b6000806000606084860312156132d957600080fd5b83356132e481612bde565b92506132f26020850161324c565b9150604084013561330281613050565b809150509250925092565b6000806040838503121561332057600080fd5b823561332b81612bde565b915060208301356003811061333f57600080fd5b809150509250929050565b60008083601f84011261335c57600080fd5b5081356001600160401b0381111561337357600080fd5b60208301915083602082850101111561338b57600080fd5b9250929050565b600080600080600080600060a0888a0312156133ad57600080fd5b87356133b881612bde565b965060208801356001600160401b03808211156133d457600080fd5b6133e08b838c01612b13565b975060408a01359150808211156133f657600080fd5b6134028b838c01612e1d565b965060608a013591508082111561341857600080fd5b6134248b838c0161334a565b909650945060808a013591508082111561343d57600080fd5b5061344a8a828b0161334a565b989b979a50959850939692959293505050565b6000806040838503121561347057600080fd5b823561347b81612bde565b9150602083013561333f81612bde565b602081016003831061349f5761349f61316d565b91905290565b600060c082840312156134b757600080fd5b60405160c081018181106001600160401b03821117156134d9576134d9612b2b565b60405282356134e781612c26565b815260208301356134f781612bde565b6020820152604083013561350a81612bde565b6040820152606083013561351d81612bde565b60608201526080838101359082015260a0928301359281019290925250919050565b634e487b7160e01b600052603260045260246000fd5b60008235603e1983360301811261356b57600080fd5b9190910192915050565b60006040823603121561358757600080fd5b604051604081016001600160401b0382821081831117156135aa576135aa612b2b565b81604052843591506135bb82612bde565b908252602084013590808211156135d157600080fd5b506135de36828601612ce8565b60208301525092915050565b815160009082906020808601845b83811015613614578151855293820193908201906001016135f8565b50929695505050505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561112957611129613620565b60006020828403121561365b57600080fd5b815161301581612bde565b600081518084526020808501945080840160005b8381101561369b5761368d878351613197565b96509082019060010161367a565b509495945050505050565b6000815180845260005b818110156136cc576020818501810151868301820152016136b0565b506000602082860101526020601f19601f83011685010191505092915050565b600060018060a01b03808351168452602083015160c0602086015261371460c08601826136a6565b90508160408501511660408601526060840151858203606087015261373982826136a6565b91505081608085015116608086015260a0840151915084810360a086015261376181836136a6565b95945050505050565b60006101008251845260018060a01b036020840151166020850152604083015161379f60408601826001600160a01b03169052565b5060608301516137ba60608601826001600160a01b03169052565b5060808301516137d560808601826001600160a01b03169052565b5060a08301518160a08601526137ed82860182613666565b91505060c083015184820360c08601526138078282613666565b91505060e083015184820360e086015261376182826136ec565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60408152600061385d604083018661376a565b8281036020840152613870818587613821565b9695505050505050565b60006020828403121561388c57600080fd5b815161301581613050565b6060815260006138aa606083018761376a565b82810360208401526138bd818688613821565b91505060018060a01b038316604083015295945050505050565b600082601f8301126138e857600080fd5b815160206138f8612c5483612c03565b82815260079290921b8401810191818101908684111561391757600080fd5b8286015b84811015612cdd57608081890312156139345760008081fd5b61393c612b41565b815161394781612c26565b81528185015161395681612bde565b81860152604082810151908201526060808301519082015283529183019160800161391b565b6000806000606080858703121561399257600080fd5b84516001600160401b03808211156139a957600080fd5b6139b5888389016138d7565b95506020915081870151818111156139cc57600080fd5b6139d889828a016138d7565b955050604080880151828111156139ee57600080fd5b88019150601f82018913613a0157600080fd5b8151613a0f612c5482612c03565b81815260c0918202840185019185820191908c841115613a2e57600080fd5b948601945b83861015613ab65780868e031215613a4b5760008081fd5b613a53612b69565b8651613a5e81612c26565b815286880151613a6d81612bde565b8189015286860151613a7e81612bde565b8187015286890151613a8f81612bde565b818a01526080878101519082015260a0808801519082015283529485019491860191613a33565b50809750505050505050509250925092565b600060208284031215613ada57600080fd5b813561301581613050565b6000808335601e19843603018112613afc57600080fd5b8301803591506001600160401b03821115613b1657600080fd5b6020019150600581901b360382131561338b57600080fd5b6000808335601e19843603018112613b4557600080fd5b8301803591506001600160401b03821115613b5f57600080fd5b60200191503681900382131561338b57600080fd5b6060808252855182820181905260009190608090818501906020808b01865b83811015613bf4578151613ba8868251613183565b808401516001600160a01b0390811687860152604080830151821690880152888201511688870152868101518787015260a0908101519086015260c09094019390820190600101613b93565b50508683039087015250613c08818961376a565b925050508281036040840152613c1f818587613821565b979650505050505050565b600060208284031215613c3c57600080fd5b81516001600160e01b03198116811461301557600080fd5b8181038181111561112957611129613620565b600060208284031215613c7957600080fd5b813561301581612c26565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b828152604060208201526000612831604083018461376a565b602081526000613015602083018461376a565b604081526000613cfb604083018561376a565b905060018060a01b0383166020830152939250505056fea2646970667358221220e85114ad197bfdcee5b3dc1561d5552dcb933e422f7f686446265774c9b8363b64736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000adc04c56bf30ac9d3c0aaf14dc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000009f23809459e3565f86d3329e7fd8309e9a58b26c
-----Decoded View---------------
Arg [0] : seaport_ (address): 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC
Arg [1] : stargate_ (address): 0x0000000000000000000000000000000000000000
Arg [2] : owner_ (address): 0x9F23809459e3565f86d3329E7fD8309e9a58b26C
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000adc04c56bf30ac9d3c0aaf14dc
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 0000000000000000000000009f23809459e3565f86d3329e7fd8309e9a58b26c
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 29 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.