编译器
0.8.20+commit.a1b79de6
文件 1 的 27:Address.sol
pragma solidity ^0.8.20;
library Address {
error AddressInsufficientBalance(address account);
error AddressEmptyCode(address target);
error FailedInnerCall();
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
文件 2 的 27:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 3 的 27:ECDSA.sol
pragma solidity ^0.8.20;
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
error ECDSAInvalidSignature();
error ECDSAInvalidSignatureLength(uint256 length);
error ECDSAInvalidSignatureS(bytes32 s);
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError, bytes32) {
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return;
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}
文件 4 的 27:EIP712.sol
pragma solidity ^0.8.20;
import {MessageHashUtils} from "./MessageHashUtils.sol";
import {ShortStrings, ShortString} from "../ShortStrings.sol";
import {IERC5267} from "../../interfaces/IERC5267.sol";
abstract contract EIP712 is IERC5267 {
using ShortStrings for *;
bytes32 private constant TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
string private _nameFallback;
string private _versionFallback;
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
}
function eip712Domain()
public
view
virtual
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f",
_EIP712Name(),
_EIP712Version(),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
function _EIP712Name() internal view returns (string memory) {
return _name.toStringWithFallback(_nameFallback);
}
function _EIP712Version() internal view returns (string memory) {
return _version.toStringWithFallback(_versionFallback);
}
}
文件 5 的 27:IERC1271.sol
pragma solidity ^0.8.20;
interface IERC1271 {
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}
文件 6 的 27:IERC20.sol
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 7 的 27:IERC20Metadata.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 8 的 27:IERC20Permit.sol
pragma solidity ^0.8.20;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 9 的 27:IERC5267.sol
pragma solidity ^0.8.20;
interface IERC5267 {
event EIP712DomainChanged();
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}
文件 10 的 27:ListHelper.sol
pragma solidity =0.8.20;
import "contracts/libraries/OTSeaErrors.sol";
abstract contract ListHelper {
uint16 internal constant LOOP_LIMIT = 500;
bool internal constant ALLOW_ZERO = true;
bool internal constant DISALLOW_ZERO = false;
error InvalidStart();
error InvalidEnd();
error InvalidSequence();
modifier onlyValidSequence(
uint256 _start,
uint256 _end,
uint256 _total,
bool _allowZero
) {
_checkSequence(_start, _end, _total, _allowZero);
_;
}
function _checkSequence(
uint256 _start,
uint256 _end,
uint256 _total,
bool _allowZero
) private pure {
if (_allowZero) {
if (_start >= _total) revert InvalidStart();
if (_end >= _total) revert InvalidEnd();
} else {
if (_start == 0 || _start > _total) revert InvalidStart();
if (_end == 0 || _end > _total) revert InvalidEnd();
}
if (_start > _end) revert InvalidStart();
if (_end - _start + 1 > LOOP_LIMIT) revert InvalidSequence();
}
function _validateListLength(uint256 _length) internal pure {
if (_length == 0 || LOOP_LIMIT < _length) revert OTSeaErrors.InvalidArrayLength();
}
}
文件 11 的 27:Math.sol
pragma solidity ^0.8.20;
library Math {
error MathOverflowedMulDiv();
enum Rounding {
Floor,
Ceil,
Trunc,
Expand
}
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
return a / b;
}
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
uint256 prod0 = x * y;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (0 - denominator);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}
文件 12 的 27:MessageHashUtils.sol
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
library MessageHashUtils {
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, messageHash)
digest := keccak256(0x00, 0x3c)
}
}
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
assembly {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}
文件 13 的 27:OTSea.sol
pragma solidity =0.8.20;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "contracts/helpers/ListHelper.sol";
import "contracts/helpers/SignatureHelper.sol";
import "contracts/helpers/TransferHelper.sol";
import "contracts/helpers/WhitelistHelper.sol";
import "contracts/libraries/OTSeaErrors.sol";
import "contracts/libraries/OTSeaLibrary.sol";
contract OTSea is
ListHelper,
Ownable,
Pausable,
ReentrancyGuard,
TransferHelper,
SignatureHelper,
WhitelistHelper
{
using SafeERC20 for IERC20;
struct NewOrder {
IERC20 token;
bool isAON;
bool withLockUp;
bool isHidden;
uint256 totalInput;
uint256 totalOutput;
}
struct Order {
address creator;
OrderType orderType;
State state;
OTSeaLibrary.FeeType feeType;
bool isAON;
bool isHidden;
bool withLockUp;
IERC20 token;
uint256 totalInput;
uint256 inputTransacted;
uint256 totalOutput;
uint256 outputTransacted;
}
struct FeeDetailsSignature {
bytes signature;
uint256 expiresAt;
OTSeaLibrary.FeeType feeType;
}
struct Trade {
uint72 orderID;
uint256 amountToSwap;
uint256 totalOutput;
}
struct Partner {
address account;
bool isLockUpOverrideEnabled;
}
struct LockUp {
address token;
uint88 unlockAt;
uint256 amount;
uint256 withdrawn;
}
struct ClaimLockUp {
uint256 index;
uint256 amount;
}
enum State {
Open,
Fulfilled,
Cancelled
}
enum OrderType {
Buy,
Sell
}
uint16 private constant MIN_PARTNER_FEE = 1000;
uint16 private constant MAX_PARTNER_FEE = 5000;
uint8 private constant MAX_TRADES_UPPER_LIMIT = 100;
uint8 private constant MAX_CANCELLATIONS = 100;
uint8 private constant MIN_LOCKUP_TIME = 1 minutes;
uint16 private constant MAX_LOCKUP_TIME = 1 hours;
bytes32 private constant FEE_DETAILS_SIGNATURE_TYPE =
keccak256("FeeDetails(address account,uint256 expiresAt,uint8 feeType)");
address private _revenueDistributor;
uint72 private _totalOrders;
uint8 private _fishFee = 100;
uint8 private _whaleFee = 30;
uint8 private _maxTrades = 10;
uint16 private _partnerFee = 3000;
uint16 private _lockupPeriod = 5 minutes;
mapping(uint72 => Order) private _orders;
mapping(address => Partner) private _partners;
mapping(address => LockUp[]) private _lockUps;
mapping(address => bool) private _blacklist;
error UnlockDateNotReached(uint256 index);
error LockUpNotAllowed();
error OrderBlacklisted();
error InvalidTradeOrderType();
error OrderNotFound(uint72 orderID);
event FeesUpdated(uint8 fishFee, uint8 whaleFee, uint16 partnerFee);
event MaxTradesUpdated(uint8 maxSwaps);
event PartnerUpdated(address indexed token, Partner partner);
event LockUpOverrideUpdated(address indexed account, address indexed token, bool enforced);
event LockupPeriodUpdated(uint16 time);
event BlacklistUpdated(address indexed account, bool operation);
event BuyOrderCreated(
uint72 indexed orderID,
address indexed creator,
NewOrder newOrder,
uint8 decimals
);
event SellOrderCreated(
uint72 indexed orderID,
address indexed creator,
NewOrder newOrder,
uint256 actualTotalInput,
uint256 actualTotalOutput,
OTSeaLibrary.FeeType feeType,
uint8 decimals
);
event SwappedETHForTokens(
address indexed account,
address indexed token,
Trade[] trades,
uint256 swapped,
uint256 received,
uint256 claimable
);
event SwappedTokensForETH(
address indexed account,
address indexed token,
Trade[] trades,
uint256 swapped,
uint256 received,
OTSeaLibrary.FeeType feeType
);
event Traded(
uint72 indexed orderID,
address indexed account,
uint256 swapped,
uint256 received
);
event LockUpsClaimed(address indexed account, address indexed receiver, ClaimLockUp[] claims);
event OrderPriceUpdated(uint72 indexed orderID, uint256 newTotalOutput);
event OrderLockUpUpdated(uint72 indexed orderID, bool enforced);
event CancelledOrders(uint72[] orderIDs);
event RevenueTransferred(uint256 eth);
event PartnerFeePaid(address indexed token, address indexed partner, uint256 eth);
modifier onlyOrderCreator(uint72 _orderID) {
_checkCallerIsOrderCreator(_orderID);
_;
}
modifier whenNotBlacklisted() {
_checkCallerIsNotBlacklisted();
_;
}
constructor(
address _multiSigAdmin,
address revenueDistributor_,
address _signer
) Ownable(_multiSigAdmin) SignatureHelper("OTSea", "v1.0.0", _signer) {
if (address(revenueDistributor_) == address(0)) revert OTSeaErrors.InvalidAddress();
_revenueDistributor = revenueDistributor_;
}
function setRevenueDistributor(address revenueDistributor_) external onlyOwner {
if (address(_revenueDistributor) == address(0)) revert OTSeaErrors.InvalidAddress();
_revenueDistributor = revenueDistributor_;
}
function pauseContract() external onlyOwner {
_pause();
}
function unpauseContract() external onlyOwner {
_unpause();
}
function setFees(
uint8 _newFishFee,
uint8 _newWhaleFee,
uint16 _newPartnerFee
) external onlyOwner {
if (
_fishFee < _newFishFee ||
_whaleFee < _newWhaleFee ||
_newFishFee < _newWhaleFee ||
_newPartnerFee < MIN_PARTNER_FEE ||
MAX_PARTNER_FEE < _newPartnerFee
) revert OTSeaErrors.InvalidFee();
_fishFee = _newFishFee;
_whaleFee = _newWhaleFee;
_partnerFee = _newPartnerFee;
emit FeesUpdated(_newFishFee, _newWhaleFee, _newPartnerFee);
}
function setMaxTrades(uint8 maxTrades_) external onlyOwner {
if (maxTrades_ == 0 || MAX_TRADES_UPPER_LIMIT < maxTrades_)
revert OTSeaErrors.InvalidAmount();
_maxTrades = maxTrades_;
emit MaxTradesUpdated(maxTrades_);
}
function updatePartner(address _token, Partner calldata _partner) external onlyOwner {
if (_token == address(0)) revert OTSeaErrors.InvalidAddress();
if (
_partners[_token].account == _partner.account &&
_partners[_token].isLockUpOverrideEnabled == _partner.isLockUpOverrideEnabled
) revert OTSeaErrors.Unchanged();
if (_partner.account == address(0) && _partner.isLockUpOverrideEnabled)
revert OTSeaErrors.NotAvailable();
_partners[_token] = Partner(_partner.account, _partner.isLockUpOverrideEnabled);
emit PartnerUpdated(_token, _partner);
}
function updateLockUpOverride(address _token, bool _enforce) external {
Partner storage partner = _partners[_token];
if (partner.account == address(0)) revert OTSeaErrors.NotAvailable();
if (partner.account != _msgSender() && owner() != _msgSender())
revert OTSeaErrors.Unauthorized();
if (partner.isLockUpOverrideEnabled == _enforce) revert OTSeaErrors.Unchanged();
partner.isLockUpOverrideEnabled = _enforce;
emit LockUpOverrideUpdated(_token, _msgSender(), _enforce);
}
function setLockupPeriod(uint16 _time) external onlyOwner {
if (_time < MIN_LOCKUP_TIME || MAX_LOCKUP_TIME < _time) revert OTSeaErrors.InvalidAmount();
_lockupPeriod = _time;
emit LockupPeriodUpdated(_time);
}
function blacklistAccount(address _account, bool _operation) external onlyOwner {
if (_account == address(0)) revert OTSeaErrors.InvalidAddress();
if (_blacklist[_account] == _operation) revert OTSeaErrors.Unchanged();
_blacklist[_account] = _operation;
emit BlacklistUpdated(_account, _operation);
}
function createBuyOrder(
NewOrder calldata _newOrder,
address[] calldata _whitelist
) external payable whenNotPaused whenNotBlacklisted {
if (address(_newOrder.token) == address(0)) revert OTSeaErrors.InvalidAddress();
if (msg.value != _newOrder.totalInput) revert OTSeaErrors.InvalidETH(_newOrder.totalInput);
uint72 orderID = _createBuyOrder(_newOrder);
if (_whitelist.length != 0) {
_initializeWhitelist(orderID, _whitelist);
}
}
function createSellOrder(
NewOrder calldata _newOrder,
address[] calldata _whitelist,
FeeDetailsSignature calldata _feeDetailsSignature
) external nonReentrant whenNotPaused whenNotBlacklisted {
if (address(_newOrder.token) == address(0)) revert OTSeaErrors.InvalidAddress();
OTSeaLibrary.FeeType feeType = _retrieveFeeDetails(_feeDetailsSignature);
uint72 orderID = _createSellOrder(_newOrder, feeType);
if (_whitelist.length != 0) {
_initializeWhitelist(orderID, _whitelist);
}
}
function swapETHForTokens(
IERC20 _token,
Trade[] calldata _trades,
NewOrder calldata _newOrder,
bool _allowLockUps,
uint16 _expectedLockupPeriod
) external payable nonReentrant whenNotPaused whenNotBlacklisted {
if (_allowLockUps && _expectedLockupPeriod != _lockupPeriod)
revert OTSeaErrors.ExpectationMismatch();
(
uint256 totalAmountToSwap,
uint256 totalAmountToReceive,
uint256 totalAmountToClaim,
uint256 totalRevenue
) = _executeBuy(_token, _trades, _allowLockUps);
if (_newOrder.token == _token) {
if (totalAmountToSwap + _newOrder.totalInput != msg.value)
revert OTSeaErrors.InvalidETH(totalAmountToSwap + _newOrder.totalInput);
_createBuyOrder(_newOrder);
} else if (totalAmountToSwap != msg.value) {
revert OTSeaErrors.InvalidETH(totalAmountToSwap);
}
_transferRevenue(totalRevenue, address(_token));
if (totalAmountToClaim != 0) {
_lockUps[_msgSender()].push(
LockUp(
address(_token),
uint88(block.timestamp + _lockupPeriod),
totalAmountToClaim,
0
)
);
}
if (totalAmountToReceive != 0) {
_token.safeTransfer(_msgSender(), totalAmountToReceive);
}
emit SwappedETHForTokens(
_msgSender(),
address(_token),
_trades,
totalAmountToSwap,
totalAmountToReceive,
totalAmountToClaim
);
}
function swapTokensForETH(
IERC20 _token,
Trade[] calldata _trades,
NewOrder calldata _newOrder,
FeeDetailsSignature calldata _feeDetailsSignature
) external nonReentrant whenNotPaused whenNotBlacklisted {
OTSeaLibrary.FeeType feeType = _retrieveFeeDetails(_feeDetailsSignature);
(uint256 totalAmountToSwap, uint256 totalAmountToReceive) = _executeSell(_token, _trades);
if (_newOrder.token == _token) {
_createSellOrder(_newOrder, feeType);
}
uint256 revenue = _handleETHPayment(_msgSender(), totalAmountToReceive, feeType);
_transferRevenue(revenue, address(_token));
emit SwappedTokensForETH(
_msgSender(),
address(_token),
_trades,
totalAmountToSwap,
totalAmountToReceive,
feeType
);
}
function claimLockUps(address _receiver, ClaimLockUp[] calldata _claims) external {
uint256 total = _lockUps[_msgSender()].length;
if (total == 0) revert OTSeaErrors.NotAvailable();
uint256 length = _claims.length;
_validateListLength(length);
for (uint256 i; i < length; ) {
ClaimLockUp calldata _claim = _claims[i];
if (total <= _claim.index) revert OTSeaErrors.InvalidIndex(i);
LockUp memory lockUp = _lockUps[_msgSender()][_claim.index];
if (block.timestamp < lockUp.unlockAt) revert UnlockDateNotReached(i);
uint256 remaining = lockUp.amount - lockUp.withdrawn;
if (_claim.amount == 0 || remaining < _claim.amount)
revert OTSeaErrors.InvalidAmountAtIndex(i);
_lockUps[_msgSender()][_claim.index].withdrawn += _claim.amount;
IERC20(lockUp.token).safeTransfer(_receiver, _claim.amount);
unchecked {
i++;
}
}
emit LockUpsClaimed(_msgSender(), _receiver, _claims);
}
function claimLockUpByToken(
IERC20 _token,
address _receiver,
ClaimLockUp[] calldata _claims
) external {
if (address(_token) == address(0)) revert OTSeaErrors.InvalidAddress();
uint256 total = _lockUps[_msgSender()].length;
if (total == 0) revert OTSeaErrors.NotAvailable();
uint256 length = _claims.length;
_validateListLength(length);
uint256 totalToClaim;
for (uint256 i; i < length; ) {
ClaimLockUp calldata _claim = _claims[i];
if (total <= _claim.index) revert OTSeaErrors.InvalidIndex(i);
LockUp memory lockUp = _lockUps[_msgSender()][_claim.index];
if (lockUp.token != address(_token)) revert OTSeaErrors.InvalidAddressAtIndex(i);
if (block.timestamp < lockUp.unlockAt) revert UnlockDateNotReached(i);
uint256 remaining = lockUp.amount - lockUp.withdrawn;
if (_claim.amount == 0 || remaining < _claim.amount)
revert OTSeaErrors.InvalidAmountAtIndex(i);
_lockUps[_msgSender()][_claim.index].withdrawn += _claim.amount;
totalToClaim += _claim.amount;
unchecked {
i++;
}
}
_token.safeTransfer(_receiver, totalToClaim);
emit LockUpsClaimed(_msgSender(), _receiver, _claims);
}
function updatePrice(
uint72 _orderID,
uint256 _expectedRemainingInput,
uint256 _newRemainingOutput
) external onlyOrderCreator(_orderID) whenNotPaused whenNotBlacklisted {
Order storage order = _orders[_orderID];
if (order.state != State.Open) revert OTSeaErrors.NotAvailable();
if (_newRemainingOutput == 0) revert OTSeaErrors.InvalidAmount();
if (order.totalInput - order.inputTransacted != _expectedRemainingInput)
revert OTSeaErrors.ExpectationMismatch();
uint256 newTotalOutput = order.outputTransacted + _newRemainingOutput;
order.totalOutput = newTotalOutput;
emit OrderPriceUpdated(_orderID, newTotalOutput);
}
function updateWhitelist(
uint72 _orderID,
WhitelistUpdate[] calldata _updates
) external override onlyOrderCreator(_orderID) whenNotPaused whenNotBlacklisted {
if (_orders[_orderID].state != State.Open) revert OTSeaErrors.NotAvailable();
_updateWhitelist(_orderID, _updates);
}
function updateOrderLockUp(
uint72 _orderID,
bool _enforce
) external onlyOrderCreator(_orderID) whenNotPaused whenNotBlacklisted {
Order storage order = _orders[_orderID];
if (order.state != State.Open || order.orderType == OrderType.Buy)
revert OTSeaErrors.NotAvailable();
if (order.withLockUp == _enforce) revert OTSeaErrors.Unchanged();
order.withLockUp = _enforce;
emit OrderLockUpUpdated(_orderID, _enforce);
}
function cancelOrders(uint72[] calldata _orderIDs) external nonReentrant {
uint256 total = _orderIDs.length;
if (total == 0 || MAX_CANCELLATIONS < total) revert OTSeaErrors.InvalidArrayLength();
uint256 totalETHOwed;
uint256 i;
for (i; i < total; ) {
Order storage order = _orders[_orderIDs[i]];
if (order.creator != _msgSender()) revert OTSeaErrors.Unauthorized();
if (order.state != State.Open) revert OTSeaErrors.NotAvailable();
order.state = State.Cancelled;
uint256 outstanding = order.totalInput - order.inputTransacted;
if (order.orderType == OrderType.Buy) {
totalETHOwed += outstanding;
} else {
order.token.safeTransfer(order.creator, outstanding);
}
unchecked {
i++;
}
}
if (totalETHOwed != 0) {
_safeETHTransfer(_msgSender(), totalETHOwed);
}
emit CancelledOrders(_orderIDs);
}
function cancelTokenOrders(IERC20 _token, uint72[] calldata _orderIDs) external nonReentrant {
uint256 total = _orderIDs.length;
if (total == 0 || MAX_CANCELLATIONS < total) revert OTSeaErrors.InvalidArrayLength();
uint256 totalETHOwed;
uint256 totalTokensOwed;
uint256 i;
for (i; i < total; ) {
Order storage order = _orders[_orderIDs[i]];
if (order.creator != _msgSender()) revert OTSeaErrors.Unauthorized();
if (order.state != State.Open || order.token != _token)
revert OTSeaErrors.NotAvailable();
order.state = State.Cancelled;
uint256 outstanding = order.totalInput - order.inputTransacted;
if (order.orderType == OrderType.Buy) {
totalETHOwed += outstanding;
} else {
totalTokensOwed += outstanding;
}
unchecked {
i++;
}
}
if (totalETHOwed != 0) {
_safeETHTransfer(_msgSender(), totalETHOwed);
}
if (totalTokensOwed != 0) {
_token.safeTransfer(_msgSender(), totalTokensOwed);
}
emit CancelledOrders(_orderIDs);
}
function getTotalOrders() external view returns (uint72) {
return _totalOrders;
}
function getOrder(uint72 _orderID) external view returns (Order memory order) {
_checkIDExists(_orderID);
return _orders[_orderID];
}
function getOrdersInSequence(
uint256 _start,
uint256 _end
)
external
view
onlyValidSequence(_start, _end, _totalOrders, DISALLOW_ZERO)
returns (Order[] memory orders)
{
orders = new Order[](_end - _start + 1);
uint256 index;
uint256 orderId = _start;
for (orderId; orderId <= _end; ) {
orders[index++] = _orders[uint72(orderId)];
unchecked {
orderId++;
}
}
return orders;
}
function getOrdersByIDs(
uint72[] calldata _orderIDs
) external view returns (Order[] memory orders) {
uint256 length = _orderIDs.length;
_validateListLength(length);
orders = new Order[](length);
uint256 i;
for (i; i < length; ) {
_checkIDExists(_orderIDs[i]);
orders[i] = _orders[_orderIDs[i]];
unchecked {
i++;
}
}
return orders;
}
function getLockupPeriod() public view returns (uint16) {
return _lockupPeriod;
}
function getTotalLockUps(address _account) public view returns (uint256) {
if (_account == address(0)) revert OTSeaErrors.InvalidAddress();
return _lockUps[_account].length;
}
function getLockUps(
address _account,
uint256[] calldata _indexes
) external view returns (LockUp[] memory lockUps) {
uint256 total = getTotalLockUps(_account);
uint256 length = _indexes.length;
_validateListLength(length);
lockUps = new LockUp[](length);
uint256 i;
for (i; i < length; ) {
if (total <= _indexes[i]) revert OTSeaErrors.InvalidIndex(i);
lockUps[i] = _lockUps[_account][_indexes[i]];
unchecked {
i++;
}
}
return lockUps;
}
function getFees() external view returns (uint8 fishFee, uint8 whaleFee, uint16 partnerFee) {
return (_fishFee, _whaleFee, _partnerFee);
}
function getMaxTrades() external view returns (uint8) {
return _maxTrades;
}
function getPartner(address _token) external view returns (Partner memory) {
if (_token == address(0)) revert OTSeaErrors.InvalidAddress();
return _partners[_token];
}
function isAccountBlacklisted(address _account) external view returns (bool) {
if (_account == address(0)) revert OTSeaErrors.InvalidAddress();
return _blacklist[_account];
}
function isOrderBlacklisted(uint72 _orderID) external view returns (bool) {
_checkIDExists(_orderID);
return _blacklist[_orders[_orderID].creator];
}
function _createBuyOrder(NewOrder calldata _newOrder) private returns (uint72 orderID) {
if (_newOrder.withLockUp) revert LockUpNotAllowed();
if (_newOrder.totalInput == 0 || _newOrder.totalOutput == 0)
revert OTSeaErrors.InvalidAmount();
orderID = ++_totalOrders;
_orders[orderID] = Order({
creator: _msgSender(),
orderType: OrderType.Buy,
state: State.Open,
feeType: OTSeaLibrary.FeeType.Fish,
isAON: _newOrder.isAON,
isHidden: _newOrder.isHidden,
withLockUp: false,
token: _newOrder.token,
totalInput: _newOrder.totalInput,
inputTransacted: 0,
totalOutput: _newOrder.totalOutput,
outputTransacted: 0
});
emit BuyOrderCreated(
orderID,
_msgSender(),
_newOrder,
IERC20Metadata(address(_newOrder.token)).decimals()
);
}
function _createSellOrder(
NewOrder calldata _newOrder,
OTSeaLibrary.FeeType _feeType
) private returns (uint72 orderID) {
if (_newOrder.totalInput == 0 || _newOrder.totalOutput == 0)
revert OTSeaErrors.InvalidAmount();
orderID = ++_totalOrders;
uint256 totalInput = _transferInTokens(_newOrder.token, _newOrder.totalInput);
uint256 totalOutput = totalInput == _newOrder.totalInput
? _newOrder.totalOutput
: (_newOrder.totalOutput * totalInput) / _newOrder.totalInput;
_orders[orderID] = Order({
creator: _msgSender(),
orderType: OrderType.Sell,
state: State.Open,
feeType: _feeType,
isAON: _newOrder.isAON,
isHidden: _newOrder.isHidden,
withLockUp: _newOrder.withLockUp,
token: _newOrder.token,
totalInput: totalInput,
inputTransacted: 0,
totalOutput: totalOutput,
outputTransacted: 0
});
emit SellOrderCreated(
orderID,
_msgSender(),
_newOrder,
totalInput,
totalOutput,
_feeType,
IERC20Metadata(address(_newOrder.token)).decimals()
);
}
function _executeBuy(
IERC20 _token,
Trade[] calldata _trades,
bool _allowLockUps
)
private
returns (
uint256 totalAmountToSwap,
uint256 totalAmountToReceive,
uint256 totalAmountToClaim,
uint256 totalRevenue
)
{
uint256 total = _trades.length;
if (total == 0 || _maxTrades < total) revert OTSeaErrors.InvalidArrayLength();
bool isLockUpOverrideEnabled = _partners[address(_token)].isLockUpOverrideEnabled;
if (isLockUpOverrideEnabled && !_allowLockUps) revert OTSeaErrors.ExpectationMismatch();
uint256 i;
for (i; i < total; ) {
Trade calldata trade = _trades[i];
Order storage order = _orders[trade.orderID];
if (_blacklist[order.creator]) revert OrderBlacklisted();
if (order.orderType == OrderType.Buy) revert InvalidTradeOrderType();
uint256 amountToReceive = _executeTrade(_token, trade);
totalRevenue += _handleETHPayment(order.creator, trade.amountToSwap, order.feeType);
totalAmountToSwap += trade.amountToSwap;
if (isLockUpOverrideEnabled || order.withLockUp) {
if (!_allowLockUps) revert OTSeaErrors.ExpectationMismatch();
totalAmountToClaim += amountToReceive;
} else {
totalAmountToReceive += amountToReceive;
}
unchecked {
i++;
}
}
return (totalAmountToSwap, totalAmountToReceive, totalAmountToClaim, totalRevenue);
}
function _executeSell(
IERC20 _token,
Trade[] calldata _trades
) private returns (uint256 totalAmountToSwap, uint256 totalAmountToReceive) {
uint256 total = _trades.length;
if (total == 0 || _maxTrades < total) revert OTSeaErrors.InvalidArrayLength();
uint256 i;
for (i; i < total; ) {
Trade calldata trade = _trades[i];
_checkIDExists(trade.orderID);
Order storage order = _orders[trade.orderID];
if (_blacklist[order.creator]) revert OrderBlacklisted();
if (order.orderType == OrderType.Sell) revert InvalidTradeOrderType();
uint256 amountToReceive = _executeTrade(_token, trade);
_token.safeTransferFrom(_msgSender(), order.creator, trade.amountToSwap);
totalAmountToSwap += trade.amountToSwap;
totalAmountToReceive += amountToReceive;
unchecked {
i++;
}
}
return (totalAmountToSwap, totalAmountToReceive);
}
function _executeTrade(
IERC20 _token,
Trade calldata _trade
) private returns (uint256 amountToReceive) {
Order storage order = _orders[_trade.orderID];
if (order.state != State.Open || order.token != _token) revert OTSeaErrors.NotAvailable();
if (
_getTotalWhitelisted(_trade.orderID) != 0 &&
!_checkIsWhitelisted(_msgSender(), _trade.orderID)
) revert OTSeaErrors.Unauthorized();
if (_trade.amountToSwap == 0) revert OTSeaErrors.InvalidAmount();
if (order.totalOutput != _trade.totalOutput) revert OTSeaErrors.ExpectationMismatch();
uint256 remainingInput = order.totalInput - order.inputTransacted;
uint256 remainingOutput = order.totalOutput - order.outputTransacted;
if (
order.isAON
? _trade.amountToSwap != remainingOutput
: remainingOutput < _trade.amountToSwap
) revert OTSeaErrors.InvalidPurchase();
if (_trade.amountToSwap == remainingOutput) {
amountToReceive = remainingInput;
order.state = State.Fulfilled;
} else {
amountToReceive = (remainingInput * _trade.amountToSwap) / remainingOutput;
}
order.inputTransacted += amountToReceive;
order.outputTransacted += _trade.amountToSwap;
emit Traded(_trade.orderID, _msgSender(), _trade.amountToSwap, amountToReceive);
}
function _handleETHPayment(
address _account,
uint256 _amount,
OTSeaLibrary.FeeType _feeType
) private returns (uint256 revenue) {
revenue =
(_amount * (_feeType == OTSeaLibrary.FeeType.Fish ? _fishFee : _whaleFee)) /
OTSeaLibrary.PERCENT_DENOMINATOR;
_safeETHTransfer(_account, _amount - revenue);
}
function _transferRevenue(uint256 _revenue, address _token) private {
address partner = _partners[_token].account;
if (partner != address(0)) {
uint256 fee = (_revenue * _partnerFee) / OTSeaLibrary.PERCENT_DENOMINATOR;
_revenue -= fee;
_safeETHTransfer(partner, fee);
emit PartnerFeePaid(_token, partner, fee);
}
_transferETHOrRevert(_revenueDistributor, _revenue);
emit RevenueTransferred(_revenue);
}
function _checkIDExists(uint72 _orderID) internal view override {
if (_orderID == 0 || _totalOrders < _orderID) revert OrderNotFound(_orderID);
}
function _retrieveFeeDetails(
FeeDetailsSignature calldata _feeDetailsSignature
) private view returns (OTSeaLibrary.FeeType feeType) {
if (_feeDetailsSignature.signature.length == 0) {
return feeType;
}
bytes memory data = abi.encode(
FEE_DETAILS_SIGNATURE_TYPE,
_msgSender(),
_feeDetailsSignature.expiresAt,
_feeDetailsSignature.feeType
);
_checkSignature(data, _feeDetailsSignature.signature, _feeDetailsSignature.expiresAt);
return _feeDetailsSignature.feeType;
}
function _checkCallerIsOrderCreator(uint72 _orderID) private view {
_checkIDExists(_orderID);
if (_orders[_orderID].creator != _msgSender()) revert OTSeaErrors.Unauthorized();
}
function _checkCallerIsNotBlacklisted() private view {
if (_blacklist[_msgSender()]) revert OTSeaErrors.Unauthorized();
}
}
文件 14 的 27:OTSeaErrors.sol
pragma solidity =0.8.20;
library OTSeaErrors {
error InvalidAmount();
error InvalidAddress();
error InvalidIndex(uint256 index);
error InvalidAmountAtIndex(uint256 index);
error InvalidAddressAtIndex(uint256 index);
error DuplicateAddressAtIndex(uint256 index);
error AddressNotFoundAtIndex(uint256 index);
error Unauthorized();
error ExpectationMismatch();
error InvalidArrayLength();
error InvalidFee();
error NotAvailable();
error InvalidPurchase();
error InvalidETH(uint256 expected);
error Unchanged();
}
文件 15 的 27:OTSeaLibrary.sol
pragma solidity =0.8.20;
library OTSeaLibrary {
enum FeeType {
Fish,
Whale
}
uint16 internal constant PERCENT_DENOMINATOR = 10000;
address internal constant DEAD_ADDRESS = address(0xdead);
}
文件 16 的 27:Ownable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 17 的 27:Pausable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Pausable is Context {
bool private _paused;
event Paused(address account);
event Unpaused(address account);
error EnforcedPause();
error ExpectedPause();
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 18 的 27:ReentrancyGuard.sol
pragma solidity ^0.8.20;
abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
_status = ENTERED;
}
function _nonReentrantAfter() private {
_status = NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
文件 19 的 27:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}
文件 20 的 27:ShortStrings.sol
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.sol";
type ShortString is bytes32;
library ShortStrings {
bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
string memory str = new string(32);
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(FALLBACK_SENTINEL);
}
}
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}
文件 21 的 27:SignatureChecker.sol
pragma solidity ^0.8.20;
import {ECDSA} from "./ECDSA.sol";
import {IERC1271} from "../../interfaces/IERC1271.sol";
library SignatureChecker {
function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
(address recovered, ECDSA.RecoverError error, ) = ECDSA.tryRecover(hash, signature);
return
(error == ECDSA.RecoverError.NoError && recovered == signer) ||
isValidERC1271SignatureNow(signer, hash, signature);
}
function isValidERC1271SignatureNow(
address signer,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
(bool success, bytes memory result) = signer.staticcall(
abi.encodeCall(IERC1271.isValidSignature, (hash, signature))
);
return (success &&
result.length >= 32 &&
abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
}
}
文件 22 的 27:SignatureHelper.sol
pragma solidity =0.8.20;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import "contracts/libraries/OTSeaErrors.sol";
abstract contract SignatureHelper is EIP712, Ownable {
address public signer;
error ExpiredSignature();
error InvalidSignature();
error SignatureRequired();
event SignerUpdated(address signer);
constructor(
string memory _name,
string memory _version,
address _signer
) EIP712(_name, _version) {
if (_signer == address(0)) revert OTSeaErrors.InvalidAddress();
signer = _signer;
}
function setSigner(address _signer) external onlyOwner {
if (_signer == address(0)) revert OTSeaErrors.InvalidAddress();
signer = _signer;
emit SignerUpdated(_signer);
}
function _checkSignature(
bytes memory _data,
bytes calldata _signature,
uint256 _expiration
) internal view {
if (_expiration < block.number) revert ExpiredSignature();
if (
!SignatureChecker.isValidSignatureNow(
signer,
_hashTypedDataV4(keccak256(_data)),
_signature
)
) revert InvalidSignature();
}
}
文件 23 的 27:SignedMath.sol
pragma solidity ^0.8.20;
library SignedMath {
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
function average(int256 a, int256 b) internal pure returns (int256) {
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
function abs(int256 n) internal pure returns (uint256) {
unchecked {
return uint256(n >= 0 ? n : -n);
}
}
}
文件 24 的 27:StorageSlot.sol
pragma solidity ^0.8.20;
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly {
r.slot := slot
}
}
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly {
r.slot := slot
}
}
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly {
r.slot := slot
}
}
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly {
r.slot := slot
}
}
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly {
r.slot := slot
}
}
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
assembly {
r.slot := store.slot
}
}
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly {
r.slot := slot
}
}
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
assembly {
r.slot := store.slot
}
}
}
文件 25 的 27:Strings.sol
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
error StringsInsufficientHexLength(uint256 value, uint256 length);
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}
文件 26 的 27:TransferHelper.sol
pragma solidity =0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "contracts/libraries/OTSeaErrors.sol";
contract TransferHelper is Context {
using SafeERC20 for IERC20;
mapping(address => uint256) private _maroonedETH;
error NativeTransferFailed();
event MaroonedETH(address account, uint256 amount);
event MaroonedETHClaimed(address account, address receiver, uint256 amount);
function claimMaroonedETH(address _receiver) external {
if (_receiver == address(0)) revert OTSeaErrors.InvalidAddress();
uint256 amount = _maroonedETH[_msgSender()];
if (amount == 0) revert OTSeaErrors.NotAvailable();
_maroonedETH[_msgSender()] = 0;
_transferETHOrRevert(_receiver, amount);
emit MaroonedETHClaimed(_msgSender(), _receiver, amount);
}
function getMaroonedETH(address _account) external view returns (uint256) {
if (_account == address(0)) revert OTSeaErrors.InvalidAddress();
return _maroonedETH[_account];
}
function _safeETHTransfer(address _account, uint256 _amount) internal {
(bool success, ) = _account.call{value: _amount}("");
if (!success) {
_maroonedETH[_account] += _amount;
emit MaroonedETH(_account, _amount);
}
}
function _transferETHOrRevert(address _account, uint256 _amount) internal {
(bool success, ) = _account.call{value: _amount}("");
if (!success) revert NativeTransferFailed();
}
function _transferInTokens(IERC20 _token, uint256 _amount) internal returns (uint256) {
uint256 balanceBefore = _token.balanceOf(address(this));
_token.safeTransferFrom(_msgSender(), address(this), _amount);
return _token.balanceOf(address(this)) - balanceBefore;
}
}
文件 27 的 27:WhitelistHelper.sol
pragma solidity =0.8.20;
import "contracts/helpers/ListHelper.sol";
import "contracts/libraries/OTSeaErrors.sol";
abstract contract WhitelistHelper is ListHelper {
struct WhitelistUpdate {
address account;
bool operation;
}
mapping(uint72 => mapping(address => uint256)) private _whitelistIDs;
mapping(uint72 => address[]) private _whitelists;
event WhitelistUpdated(uint72 indexed id, uint256 totalWhitelist);
function updateWhitelist(uint72 _id, WhitelistUpdate[] calldata _updates) external virtual;
function getTotalWhitelisted(uint72 _id) external view returns (uint256) {
_checkIDExists(_id);
return _getTotalWhitelisted(_id);
}
function getWhitelist(
uint72 _id,
uint256 _start,
uint256 _end
)
external
view
onlyValidSequence(_start, _end, _getTotalWhitelisted(_id), DISALLOW_ZERO)
returns (address[] memory whitelist)
{
whitelist = new address[](_end - _start + 1);
uint256 index;
uint256 whitelistIndex = _start - 1;
for (whitelistIndex; whitelistIndex < _end; ) {
whitelist[index] = _whitelists[_id][whitelistIndex];
unchecked {
index++;
whitelistIndex++;
}
}
return whitelist;
}
function checkIsWhitelisted(address _account, uint72 _id) external view returns (bool) {
if (_account == address(0)) revert OTSeaErrors.InvalidAddress();
_checkIDExists(_id);
return _checkIsWhitelisted(_account, _id);
}
function checkMultipleIsWhitelisted(
address _account,
uint72[] calldata _ids
) external view returns (bool[] memory isWhitelisted) {
uint256 total = _ids.length;
_validateListLength(total);
if (_account == address(0)) revert OTSeaErrors.InvalidAddress();
isWhitelisted = new bool[](total);
uint256 i;
for (i; i < total; ) {
_checkIDExists(_ids[i]);
isWhitelisted[i] = _checkIsWhitelisted(_account, _ids[i]);
unchecked {
i++;
}
}
return isWhitelisted;
}
function _initializeWhitelist(uint72 _id, address[] calldata _whitelist) internal {
uint256 total = _whitelist.length;
if (LOOP_LIMIT < total) revert OTSeaErrors.InvalidArrayLength();
uint256 i;
for (i; i < total; ) {
if (_whitelist[i] == address(0)) revert OTSeaErrors.InvalidAddressAtIndex(i);
if (_whitelistIDs[_id][_whitelist[i]] != 0)
revert OTSeaErrors.DuplicateAddressAtIndex(i);
_whitelistIDs[_id][_whitelist[i]] = i + 1;
unchecked {
i++;
}
}
_whitelists[_id] = _whitelist;
emit WhitelistUpdated(_id, total);
}
function _updateWhitelist(uint72 _id, WhitelistUpdate[] calldata _updates) internal {
uint256 total = _updates.length;
_validateListLength(total);
address[] storage orderWhitelist = _whitelists[_id];
uint256 totalWhitelisted = _whitelists[_id].length;
uint256 i;
for (i; i < total; ) {
if (_updates[i].account == address(0)) revert OTSeaErrors.InvalidAddressAtIndex(i);
if (_updates[i].operation) {
if (_whitelistIDs[_id][_updates[i].account] != 0)
revert OTSeaErrors.DuplicateAddressAtIndex(i);
_whitelistIDs[_id][_updates[i].account] = ++totalWhitelisted;
orderWhitelist.push(_updates[i].account);
} else {
uint256 id = _whitelistIDs[_id][_updates[i].account];
if (id == 0) revert OTSeaErrors.AddressNotFoundAtIndex(i);
address lastAddress = orderWhitelist[totalWhitelisted - 1];
if (_updates[i].account != lastAddress) {
orderWhitelist[id - 1] = lastAddress;
_whitelistIDs[_id][lastAddress] = id;
}
_whitelistIDs[_id][_updates[i].account] = 0;
orderWhitelist.pop();
totalWhitelisted--;
}
unchecked {
i++;
}
}
emit WhitelistUpdated(_id, totalWhitelisted);
}
function _getTotalWhitelisted(uint72 _id) internal view returns (uint256) {
return _whitelists[_id].length;
}
function _checkIsWhitelisted(address _account, uint72 _id) internal view returns (bool) {
return _whitelistIDs[_id][_account] != 0;
}
function _checkIDExists(uint72 _id) internal view virtual;
}
{
"compilationTarget": {
"contracts/otc/OTSea.sol": "OTSea"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_multiSigAdmin","type":"address"},{"internalType":"address","name":"revenueDistributor_","type":"address"},{"internalType":"address","name":"_signer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"AddressNotFoundAtIndex","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"DuplicateAddressAtIndex","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectationMismatch","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"ExpiredSignature","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"InvalidAddressAtIndex","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"InvalidAmountAtIndex","type":"error"},{"inputs":[],"name":"InvalidArrayLength","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InvalidETH","type":"error"},{"inputs":[],"name":"InvalidEnd","type":"error"},{"inputs":[],"name":"InvalidFee","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"InvalidIndex","type":"error"},{"inputs":[],"name":"InvalidPurchase","type":"error"},{"inputs":[],"name":"InvalidSequence","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidStart","type":"error"},{"inputs":[],"name":"InvalidTradeOrderType","type":"error"},{"inputs":[],"name":"LockUpNotAllowed","type":"error"},{"inputs":[],"name":"NativeTransferFailed","type":"error"},{"inputs":[],"name":"NotAvailable","type":"error"},{"inputs":[],"name":"OrderBlacklisted","type":"error"},{"inputs":[{"internalType":"uint72","name":"orderID","type":"uint72"}],"name":"OrderNotFound","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SignatureRequired","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"Unchanged","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"UnlockDateNotReached","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"operation","type":"bool"}],"name":"BlacklistUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint72","name":"orderID","type":"uint72"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"bool","name":"isAON","type":"bool"},{"internalType":"bool","name":"withLockUp","type":"bool"},{"internalType":"bool","name":"isHidden","type":"bool"},{"internalType":"uint256","name":"totalInput","type":"uint256"},{"internalType":"uint256","name":"totalOutput","type":"uint256"}],"indexed":false,"internalType":"struct OTSea.NewOrder","name":"newOrder","type":"tuple"},{"indexed":false,"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"BuyOrderCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint72[]","name":"orderIDs","type":"uint72[]"}],"name":"CancelledOrders","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"fishFee","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"whaleFee","type":"uint8"},{"indexed":false,"internalType":"uint16","name":"partnerFee","type":"uint16"}],"name":"FeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"enforced","type":"bool"}],"name":"LockUpOverrideUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"indexed":false,"internalType":"struct OTSea.ClaimLockUp[]","name":"claims","type":"tuple[]"}],"name":"LockUpsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"time","type":"uint16"}],"name":"LockupPeriodUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"MaroonedETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"MaroonedETHClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"maxSwaps","type":"uint8"}],"name":"MaxTradesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint72","name":"orderID","type":"uint72"},{"indexed":false,"internalType":"bool","name":"enforced","type":"bool"}],"name":"OrderLockUpUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint72","name":"orderID","type":"uint72"},{"indexed":false,"internalType":"uint256","name":"newTotalOutput","type":"uint256"}],"name":"OrderPriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"partner","type":"address"},{"indexed":false,"internalType":"uint256","name":"eth","type":"uint256"}],"name":"PartnerFeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"isLockUpOverrideEnabled","type":"bool"}],"indexed":false,"internalType":"struct OTSea.Partner","name":"partner","type":"tuple"}],"name":"PartnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"eth","type":"uint256"}],"name":"RevenueTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint72","name":"orderID","type":"uint72"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"bool","name":"isAON","type":"bool"},{"internalType":"bool","name":"withLockUp","type":"bool"},{"internalType":"bool","name":"isHidden","type":"bool"},{"internalType":"uint256","name":"totalInput","type":"uint256"},{"internalType":"uint256","name":"totalOutput","type":"uint256"}],"indexed":false,"internalType":"struct OTSea.NewOrder","name":"newOrder","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"actualTotalInput","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"actualTotalOutput","type":"uint256"},{"indexed":false,"internalType":"enum OTSeaLibrary.FeeType","name":"feeType","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"SellOrderCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"signer","type":"address"}],"name":"SignerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"uint72","name":"orderID","type":"uint72"},{"internalType":"uint256","name":"amountToSwap","type":"uint256"},{"internalType":"uint256","name":"totalOutput","type":"uint256"}],"indexed":false,"internalType":"struct OTSea.Trade[]","name":"trades","type":"tuple[]"},{"indexed":false,"internalType":"uint256","name":"swapped","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"received","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"claimable","type":"uint256"}],"name":"SwappedETHForTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"uint72","name":"orderID","type":"uint72"},{"internalType":"uint256","name":"amountToSwap","type":"uint256"},{"internalType":"uint256","name":"totalOutput","type":"uint256"}],"indexed":false,"internalType":"struct OTSea.Trade[]","name":"trades","type":"tuple[]"},{"indexed":false,"internalType":"uint256","name":"swapped","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"received","type":"uint256"},{"indexed":false,"internalType":"enum OTSeaLibrary.FeeType","name":"feeType","type":"uint8"}],"name":"SwappedTokensForETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint72","name":"orderID","type":"uint72"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"swapped","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"received","type":"uint256"}],"name":"Traded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint72","name":"id","type":"uint72"},{"indexed":false,"internalType":"uint256","name":"totalWhitelist","type":"uint256"}],"name":"WhitelistUpdated","type":"event"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_operation","type":"bool"}],"name":"blacklistAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint72[]","name":"_orderIDs","type":"uint72[]"}],"name":"cancelOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"uint72[]","name":"_orderIDs","type":"uint72[]"}],"name":"cancelTokenOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint72","name":"_id","type":"uint72"}],"name":"checkIsWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint72[]","name":"_ids","type":"uint72[]"}],"name":"checkMultipleIsWhitelisted","outputs":[{"internalType":"bool[]","name":"isWhitelisted","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct OTSea.ClaimLockUp[]","name":"_claims","type":"tuple[]"}],"name":"claimLockUpByToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct OTSea.ClaimLockUp[]","name":"_claims","type":"tuple[]"}],"name":"claimLockUps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"}],"name":"claimMaroonedETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"bool","name":"isAON","type":"bool"},{"internalType":"bool","name":"withLockUp","type":"bool"},{"internalType":"bool","name":"isHidden","type":"bool"},{"internalType":"uint256","name":"totalInput","type":"uint256"},{"internalType":"uint256","name":"totalOutput","type":"uint256"}],"internalType":"struct OTSea.NewOrder","name":"_newOrder","type":"tuple"},{"internalType":"address[]","name":"_whitelist","type":"address[]"}],"name":"createBuyOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"bool","name":"isAON","type":"bool"},{"internalType":"bool","name":"withLockUp","type":"bool"},{"internalType":"bool","name":"isHidden","type":"bool"},{"internalType":"uint256","name":"totalInput","type":"uint256"},{"internalType":"uint256","name":"totalOutput","type":"uint256"}],"internalType":"struct OTSea.NewOrder","name":"_newOrder","type":"tuple"},{"internalType":"address[]","name":"_whitelist","type":"address[]"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"expiresAt","type":"uint256"},{"internalType":"enum OTSeaLibrary.FeeType","name":"feeType","type":"uint8"}],"internalType":"struct OTSea.FeeDetailsSignature","name":"_feeDetailsSignature","type":"tuple"}],"name":"createSellOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFees","outputs":[{"internalType":"uint8","name":"fishFee","type":"uint8"},{"internalType":"uint8","name":"whaleFee","type":"uint8"},{"internalType":"uint16","name":"partnerFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256[]","name":"_indexes","type":"uint256[]"}],"name":"getLockUps","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint88","name":"unlockAt","type":"uint88"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"withdrawn","type":"uint256"}],"internalType":"struct OTSea.LockUp[]","name":"lockUps","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockupPeriod","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getMaroonedETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxTrades","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint72","name":"_orderID","type":"uint72"}],"name":"getOrder","outputs":[{"components":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"enum OTSea.OrderType","name":"orderType","type":"uint8"},{"internalType":"enum OTSea.State","name":"state","type":"uint8"},{"internalType":"enum OTSeaLibrary.FeeType","name":"feeType","type":"uint8"},{"internalType":"bool","name":"isAON","type":"bool"},{"internalType":"bool","name":"isHidden","type":"bool"},{"internalType":"bool","name":"withLockUp","type":"bool"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"totalInput","type":"uint256"},{"internalType":"uint256","name":"inputTransacted","type":"uint256"},{"internalType":"uint256","name":"totalOutput","type":"uint256"},{"internalType":"uint256","name":"outputTransacted","type":"uint256"}],"internalType":"struct OTSea.Order","name":"order","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint72[]","name":"_orderIDs","type":"uint72[]"}],"name":"getOrdersByIDs","outputs":[{"components":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"enum OTSea.OrderType","name":"orderType","type":"uint8"},{"internalType":"enum OTSea.State","name":"state","type":"uint8"},{"internalType":"enum OTSeaLibrary.FeeType","name":"feeType","type":"uint8"},{"internalType":"bool","name":"isAON","type":"bool"},{"internalType":"bool","name":"isHidden","type":"bool"},{"internalType":"bool","name":"withLockUp","type":"bool"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"totalInput","type":"uint256"},{"internalType":"uint256","name":"inputTransacted","type":"uint256"},{"internalType":"uint256","name":"totalOutput","type":"uint256"},{"internalType":"uint256","name":"outputTransacted","type":"uint256"}],"internalType":"struct OTSea.Order[]","name":"orders","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"getOrdersInSequence","outputs":[{"components":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"enum OTSea.OrderType","name":"orderType","type":"uint8"},{"internalType":"enum OTSea.State","name":"state","type":"uint8"},{"internalType":"enum OTSeaLibrary.FeeType","name":"feeType","type":"uint8"},{"internalType":"bool","name":"isAON","type":"bool"},{"internalType":"bool","name":"isHidden","type":"bool"},{"internalType":"bool","name":"withLockUp","type":"bool"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"totalInput","type":"uint256"},{"internalType":"uint256","name":"inputTransacted","type":"uint256"},{"internalType":"uint256","name":"totalOutput","type":"uint256"},{"internalType":"uint256","name":"outputTransacted","type":"uint256"}],"internalType":"struct OTSea.Order[]","name":"orders","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getPartner","outputs":[{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"isLockUpOverrideEnabled","type":"bool"}],"internalType":"struct OTSea.Partner","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getTotalLockUps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalOrders","outputs":[{"internalType":"uint72","name":"","type":"uint72"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint72","name":"_id","type":"uint72"}],"name":"getTotalWhitelisted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint72","name":"_id","type":"uint72"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"getWhitelist","outputs":[{"internalType":"address[]","name":"whitelist","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isAccountBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint72","name":"_orderID","type":"uint72"}],"name":"isOrderBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauseContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_newFishFee","type":"uint8"},{"internalType":"uint8","name":"_newWhaleFee","type":"uint8"},{"internalType":"uint16","name":"_newPartnerFee","type":"uint16"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_time","type":"uint16"}],"name":"setLockupPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"maxTrades_","type":"uint8"}],"name":"setMaxTrades","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"revenueDistributor_","type":"address"}],"name":"setRevenueDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"components":[{"internalType":"uint72","name":"orderID","type":"uint72"},{"internalType":"uint256","name":"amountToSwap","type":"uint256"},{"internalType":"uint256","name":"totalOutput","type":"uint256"}],"internalType":"struct OTSea.Trade[]","name":"_trades","type":"tuple[]"},{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"bool","name":"isAON","type":"bool"},{"internalType":"bool","name":"withLockUp","type":"bool"},{"internalType":"bool","name":"isHidden","type":"bool"},{"internalType":"uint256","name":"totalInput","type":"uint256"},{"internalType":"uint256","name":"totalOutput","type":"uint256"}],"internalType":"struct OTSea.NewOrder","name":"_newOrder","type":"tuple"},{"internalType":"bool","name":"_allowLockUps","type":"bool"},{"internalType":"uint16","name":"_expectedLockupPeriod","type":"uint16"}],"name":"swapETHForTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"components":[{"internalType":"uint72","name":"orderID","type":"uint72"},{"internalType":"uint256","name":"amountToSwap","type":"uint256"},{"internalType":"uint256","name":"totalOutput","type":"uint256"}],"internalType":"struct OTSea.Trade[]","name":"_trades","type":"tuple[]"},{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"bool","name":"isAON","type":"bool"},{"internalType":"bool","name":"withLockUp","type":"bool"},{"internalType":"bool","name":"isHidden","type":"bool"},{"internalType":"uint256","name":"totalInput","type":"uint256"},{"internalType":"uint256","name":"totalOutput","type":"uint256"}],"internalType":"struct OTSea.NewOrder","name":"_newOrder","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"expiresAt","type":"uint256"},{"internalType":"enum OTSeaLibrary.FeeType","name":"feeType","type":"uint8"}],"internalType":"struct OTSea.FeeDetailsSignature","name":"_feeDetailsSignature","type":"tuple"}],"name":"swapTokensForETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpauseContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"bool","name":"_enforce","type":"bool"}],"name":"updateLockUpOverride","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint72","name":"_orderID","type":"uint72"},{"internalType":"bool","name":"_enforce","type":"bool"}],"name":"updateOrderLockUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"isLockUpOverrideEnabled","type":"bool"}],"internalType":"struct OTSea.Partner","name":"_partner","type":"tuple"}],"name":"updatePartner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint72","name":"_orderID","type":"uint72"},{"internalType":"uint256","name":"_expectedRemainingInput","type":"uint256"},{"internalType":"uint256","name":"_newRemainingOutput","type":"uint256"}],"name":"updatePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint72","name":"_orderID","type":"uint72"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"operation","type":"bool"}],"internalType":"struct WhitelistHelper.WhitelistUpdate[]","name":"_updates","type":"tuple[]"}],"name":"updateWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"}]