// SPDX-License-Identifier: MITpragmasolidity ^0.8.4;/// @notice Gas optimized ECDSA wrapper./// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)libraryECDSA{
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* CUSTOM ERRORS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev The signature is invalid.errorInvalidSignature();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* CONSTANTS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev The number which `s` must be less than in order for/// the signature to be non-malleable.bytes32privateconstant _MALLEABILITY_THRESHOLD_PLUS_ONE =0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* RECOVERY OPERATIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/// Note: as of Solady version 0.0.68, these functions will// revert upon recovery failure for more safety by default./// @dev Recovers the signer's address from a message digest `hash`,/// and the `signature`.////// This function does NOT accept EIP-2098 short form signatures./// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098/// short form signatures instead.functionrecover(bytes32 hash, bytesmemory signature) internalviewreturns (address result) {
/// @solidity memory-safe-assemblyassembly {
let m :=mload(0x40) // Cache the free memory pointer.mstore(0x00, hash)
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.mstore(0x40, mload(add(signature, 0x20))) // `r`.mstore(0x60, mload(add(signature, 0x40))) // `s`.pop(
staticcall(
gas(), // Amount of gas left for the transaction.and(
// If the signature is exactly 65 bytes in length.eq(mload(signature), 65),
// If `s` in lower half order, such that the signature is not malleable.lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE)
), // Address of `ecrecover`.0x00, // Start of input.0x80, // Size of input.0x00, // Start of output.0x20// Size of output.
)
)
result :=mload(0x00)
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.ifiszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,/// and the `signature`.////// This function does NOT accept EIP-2098 short form signatures./// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098/// short form signatures instead.functionrecoverCalldata(bytes32 hash, bytescalldata signature)
internalviewreturns (address result)
{
/// @solidity memory-safe-assemblyassembly {
let m :=mload(0x40) // Cache the free memory pointer.mstore(0x00, hash)
mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.pop(
staticcall(
gas(), // Amount of gas left for the transaction.and(
// If the signature is exactly 65 bytes in length.eq(signature.length, 65),
// If `s` in lower half order, such that the signature is not malleable.lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE)
), // Address of `ecrecover`.0x00, // Start of input.0x80, // Size of input.0x00, // Start of output.0x20// Size of output.
)
)
result :=mload(0x00)
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.ifiszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,/// and the EIP-2098 short form signature defined by `r` and `vs`.////// This function only accepts EIP-2098 short form signatures./// See: https://eips.ethereum.org/EIPS/eip-2098functionrecover(bytes32 hash, bytes32 r, bytes32 vs) internalviewreturns (address result) {
/// @solidity memory-safe-assemblyassembly {
let m :=mload(0x40) // Cache the free memory pointer.mstore(0x00, hash)
mstore(0x20, add(shr(255, vs), 27)) // `v`.mstore(0x40, r)
mstore(0x60, shr(1, shl(1, vs))) // `s`.pop(
staticcall(
gas(), // Amount of gas left for the transaction.// If `s` in lower half order, such that the signature is not malleable.lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`.0x00, // Start of input.0x80, // Size of input.0x00, // Start of output.0x20// Size of output.
)
)
result :=mload(0x00)
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.ifiszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,/// and the signature defined by `v`, `r`, `s`.functionrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internalviewreturns (address result)
{
/// @solidity memory-safe-assemblyassembly {
let m :=mload(0x40) // Cache the free memory pointer.mstore(0x00, hash)
mstore(0x20, and(v, 0xff))
mstore(0x40, r)
mstore(0x60, s)
pop(
staticcall(
gas(), // Amount of gas left for the transaction.// If `s` in lower half order, such that the signature is not malleable.lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`.0x00, // Start of input.0x80, // Size of input.0x00, // Start of output.0x20// Size of output.
)
)
result :=mload(0x00)
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.ifiszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.mstore(0x40, m) // Restore the free memory pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* TRY-RECOVER OPERATIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/// WARNING!// These functions will NOT revert upon recovery failure.// Instead, they will return the zero address upon recovery failure.// It is critical that the returned address is NEVER compared against// a zero address (e.g. an uninitialized address variable)./// @dev Recovers the signer's address from a message digest `hash`,/// and the `signature`.////// This function does NOT accept EIP-2098 short form signatures./// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098/// short form signatures instead.functiontryRecover(bytes32 hash, bytesmemory signature)
internalviewreturns (address result)
{
/// @solidity memory-safe-assemblyassembly {
let m :=mload(0x40) // Cache the free memory pointer.mstore(0x00, hash)
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.mstore(0x40, mload(add(signature, 0x20))) // `r`.mstore(0x60, mload(add(signature, 0x40))) // `s`.pop(
staticcall(
gas(), // Amount of gas left for the transaction.and(
// If the signature is exactly 65 bytes in length.eq(mload(signature), 65),
// If `s` in lower half order, such that the signature is not malleable.lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE)
), // Address of `ecrecover`.0x00, // Start of input.0x80, // Size of input.0x40, // Start of output.0x20// Size of output.
)
)
mstore(0x60, 0) // Restore the zero slot.// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result :=mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,/// and the `signature`.////// This function does NOT accept EIP-2098 short form signatures./// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098/// short form signatures instead.functiontryRecoverCalldata(bytes32 hash, bytescalldata signature)
internalviewreturns (address result)
{
/// @solidity memory-safe-assemblyassembly {
let m :=mload(0x40) // Cache the free memory pointer.mstore(0x00, hash)
mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.pop(
staticcall(
gas(), // Amount of gas left for the transaction.and(
// If the signature is exactly 65 bytes in length.eq(signature.length, 65),
// If `s` in lower half order, such that the signature is not malleable.lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE)
), // Address of `ecrecover`.0x00, // Start of input.0x80, // Size of input.0x40, // Start of output.0x20// Size of output.
)
)
mstore(0x60, 0) // Restore the zero slot.// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result :=mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,/// and the EIP-2098 short form signature defined by `r` and `vs`.////// This function only accepts EIP-2098 short form signatures./// See: https://eips.ethereum.org/EIPS/eip-2098functiontryRecover(bytes32 hash, bytes32 r, bytes32 vs)
internalviewreturns (address result)
{
/// @solidity memory-safe-assemblyassembly {
let m :=mload(0x40) // Cache the free memory pointer.mstore(0x00, hash)
mstore(0x20, add(shr(255, vs), 27)) // `v`.mstore(0x40, r)
mstore(0x60, shr(1, shl(1, vs))) // `s`.pop(
staticcall(
gas(), // Amount of gas left for the transaction.// If `s` in lower half order, such that the signature is not malleable.lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`.0x00, // Start of input.0x80, // Size of input.0x40, // Start of output.0x20// Size of output.
)
)
mstore(0x60, 0) // Restore the zero slot.// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result :=mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,/// and the signature defined by `v`, `r`, `s`.functiontryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internalviewreturns (address result)
{
/// @solidity memory-safe-assemblyassembly {
let m :=mload(0x40) // Cache the free memory pointer.mstore(0x00, hash)
mstore(0x20, and(v, 0xff))
mstore(0x40, r)
mstore(0x60, s)
pop(
staticcall(
gas(), // Amount of gas left for the transaction.// If `s` in lower half order, such that the signature is not malleable.lt(s, _MALLEABILITY_THRESHOLD_PLUS_ONE), // Address of `ecrecover`.0x00, // Start of input.0x80, // Size of input.0x40, // Start of output.0x20// Size of output.
)
)
mstore(0x60, 0) // Restore the zero slot.// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result :=mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* 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.functiontoEthSignedMessageHash(bytes32 hash) internalpurereturns (bytes32 result) {
/// @solidity memory-safe-assemblyassembly {
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.functiontoEthSignedMessageHash(bytesmemory s) internalpurereturns (bytes32 result) {
/// @solidity memory-safe-assemblyassembly {
let sLength :=mload(s)
let o :=0x20mstore(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)
ifiszero(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.functionemptySignature() internalpurereturns (bytescalldata signature) {
/// @solidity memory-safe-assemblyassembly {
signature.length:=0
}
}
}
pragmasolidity ^0.8.20;/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/librarySafeMath{
/**
* @dev Multiplies two numbers, throws on overflow.
*/functionmul(uint256 a, uint256 b) internalpurereturns (uint256 c) {
if (a ==0) {
return0;
}
c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/functiondiv(uint256 a, uint256 b) internalpurereturns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0// uint256 c = a / b;// assert(a == b * c + a % b); // There is no case in which this doesn't holdreturn a / b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/functionsub(uint256 a, uint256 b) internalpurereturns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/functionadd(uint256 a, uint256 b) internalpurereturns (uint256 c) {
c = a + b;
assert(c >= a);
return c;
}
}