文件 1 的 21:AccessControl.sol
pragma solidity ^0.8.0;
import "IAccessControl.sol";
import "Context.sol";
import "Strings.sol";
import "ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
文件 2 的 21:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 3 的 21:BufferRouter.sol
pragma solidity 0.8.4;
import "ReentrancyGuard.sol";
import "AccessControl.sol";
import "SafeERC20.sol";
import "draft-IERC20Permit.sol";
import "InterfacesUD.sol";
import "ECDSA.sol";
import "Validator.sol";
contract BufferRouterUD is AccessControl, IBufferRouterUD {
using SafeERC20 for ERC20;
uint16 public constant MAX_DELAY_FOR_OPEN_TRADE = 1 minutes;
uint64 public constant MAXIMUM_PRICE_DELAY_FOR_RESOLVING = 5 seconds;
uint64 public constant QUEUE_TIME_LAG = 3 seconds;
uint256 public lastSavedQueueId = 0;
address public sfPublisher;
address public spreadPublisher;
address public admin;
IAccountRegistrar public accountRegistrar;
IPyth public pyth;
mapping(uint256 => QueuedTrade) public queuedTrades;
mapping(address => bool) public contractRegistry;
mapping(address => bool) public isKeeper;
mapping(bytes => bool) public prevSignature;
mapping(address => mapping(uint256 => uint256)) public optionIdMapping;
mapping(uint256 => QueueIdInfo) public queueIdInfo;
constructor(
address _sfPublisher,
address _spreadPublisher,
address _admin,
address _accountRegistrar,
IPyth _pyth
) {
pyth = _pyth;
sfPublisher = _sfPublisher;
spreadPublisher = _spreadPublisher;
admin = _admin;
accountRegistrar = IAccountRegistrar(_accountRegistrar);
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
function setContractRegistry(
address targetContract,
bool register
) external onlyRole(DEFAULT_ADMIN_ROLE) {
contractRegistry[targetContract] = register;
emit ContractRegistryUpdated(targetContract, register);
}
function setKeeper(
address _keeper,
bool _isActive
) external onlyRole(DEFAULT_ADMIN_ROLE) {
isKeeper[_keeper] = _isActive;
}
function approveViaSignature(
address tokenX,
address user,
uint256 queueId,
Permit memory permit
) internal returns (bool) {
IERC20Permit token = IERC20Permit(tokenX);
uint256 nonceBefore = token.nonces(user);
try
token.permit(
user,
address(this),
permit.value,
permit.deadline,
permit.v,
permit.r,
permit.s
)
{} catch Error(string memory reason) {
emit FailResolve(queueId, reason);
return false;
}
uint256 nonceAfter = token.nonces(user);
if (nonceAfter != nonceBefore + 1) {
emit FailResolve(queueId, "Router: Permit did not succeed");
return false;
}
emit ApproveRouter(
user,
nonceBefore,
permit.value,
permit.deadline,
tokenX
);
return true;
}
function revokeApprovals(RevokeParams[] calldata revokeParams) external {
for (uint256 index = 0; index < revokeParams.length; index++) {
RevokeParams memory params = revokeParams[index];
IERC20Permit token = IERC20Permit(params.tokenX);
uint256 nonceBefore = token.nonces(params.user);
try
token.permit(
params.user,
address(this),
params.permit.value,
params.permit.deadline,
params.permit.v,
params.permit.r,
params.permit.s
)
{} catch Error(string memory reason) {
emit FailRevoke(params.user, params.tokenX, reason);
}
uint256 nonceAfter = token.nonces(params.user);
if (nonceAfter != nonceBefore + 1) {
emit FailRevoke(
params.user,
params.tokenX,
"Router: Permit did not succeed"
);
}
emit RevokeRouter(
params.user,
nonceBefore,
params.permit.value,
params.permit.deadline,
params.tokenX
);
}
}
function initiateTrade(TradeParamsV2 calldata params) external {
if (!contractRegistry[params.targetContract]) {
revert("Router: Unauthorized contract");
}
IOptionsConfigUD config = IOptionsConfigUD(
IBufferBinaryOptionsUD(params.targetContract).config()
);
ERC20 tokenX = ERC20(
IBufferBinaryOptionsUD(params.targetContract).tokenX()
);
tokenX.safeTransferFrom(msg.sender, admin, config.platformFee());
lastSavedQueueId += 1;
queuedTrades[lastSavedQueueId] = QueuedTrade({
user: msg.sender,
targetContract: params.targetContract,
strike: params.strike,
slippage: params.slippage,
period: params.period,
allowPartialFill: params.allowPartialFill,
totalFee: params.totalFee,
referralCode: params.referralCode,
settlementFee: params.settlementFee,
isTradeResolved: false,
isEarlyCloseAllowed: config.isEarlyCloseAllowed(),
isAbove: params.isAbove,
limitOrder: params.limitOrder,
queueTime: block.timestamp + QUEUE_TIME_LAG
});
emit InitiateTrade(
msg.sender,
lastSavedQueueId,
params.targetContract,
params.strike,
params.slippage,
params.period,
params.allowPartialFill,
params.totalFee,
params.referralCode,
params.settlementFee,
params.isAbove
);
}
function openTrades(OpenTxn[] calldata params) external payable {
_validateKeeper();
for (uint32 index = 0; index < params.length; index++) {
TradeParams memory currentParams = params[index].tradeParams;
lastSavedQueueId = currentParams.queueId;
address user = params[index].user;
IBufferBinaryOptionsUD optionsContract = IBufferBinaryOptionsUD(
currentParams.targetContract
);
IOptionsConfigUD config = IOptionsConfigUD(
optionsContract.config()
);
ERC20 tokenX = ERC20(optionsContract.tokenX());
Permit memory permit = params[index].permit;
uint256 amountToPay = currentParams.totalFee + config.platformFee();
if (tokenX.balanceOf(user) < amountToPay) {
emit FailResolve(
currentParams.queueId,
"Router: Insufficient balance"
);
continue;
}
if (
((tokenX.allowance(user, address(this)) < amountToPay) &&
(!permit.shouldApprove)) ||
((tokenX.allowance(user, address(this)) + permit.value) <
amountToPay)
) {
emit FailResolve(
currentParams.queueId,
"Router: Incorrect allowance"
);
continue;
} else if (permit.shouldApprove) {
bool success = approveViaSignature(
address(optionsContract.tokenX()),
user,
currentParams.queueId,
permit
);
if (!success) continue;
}
if (params[index].register.shouldRegister) {
try
accountRegistrar.registerAccount(
params[index].register.oneCT,
user,
params[index].register.signature
)
{} catch Error(string memory reason) {
emit FailResolve(
currentParams.queueId,
"Router: Registration failed"
);
continue;
}
}
(address signer, uint256 nonce) = getAccountMapping(user);
(bool isValid, string memory errorResaon) = verifyTrade(
currentParams,
user,
signer,
optionsContract
);
if (!isValid) {
emit FailResolve(currentParams.queueId, errorResaon);
continue;
}
queuedTrades[currentParams.queueId] = QueuedTrade({
user: user,
targetContract: currentParams.targetContract,
strike: currentParams.strike,
slippage: currentParams.slippage,
period: currentParams.period,
allowPartialFill: currentParams.allowPartialFill,
totalFee: currentParams.totalFee,
referralCode: currentParams.referralCode,
settlementFee: currentParams.userSignedSettlementFee,
isTradeResolved: false,
isEarlyCloseAllowed: config.isEarlyCloseAllowed(),
isAbove: currentParams.isAbove,
limitOrder: currentParams.limitOrder,
queueTime: currentParams.queueTime
});
tokenX.safeTransferFrom(user, admin, config.platformFee());
prevSignature[currentParams.userSignInfo.signature] = true;
resolveTrade(
currentParams.queueId,
ResolveParams({
spread: currentParams.spread,
settlementFee: currentParams.settlementFee,
settlementFeeSignInfo: currentParams.settlementFeeSignInfo,
spreadSignInfo: currentParams.spreadSignInfo,
priceUpdateData: currentParams.priceUpdateData,
priceIds: currentParams.priceIds,
limitOrderOpenTime: currentParams
.limitOrder
.limitOrderOpenTime
})
);
}
}
function closeAnytime(
CloseAnytimeParams[] calldata closeParams
) external payable {
_validateKeeper();
for (uint32 index = 0; index < closeParams.length; index++) {
CloseAnytimeParams memory closeParam = closeParams[index];
CloseTradeParams memory params = closeParam.closeTradeParams;
IBufferBinaryOptionsUD optionsContract = IBufferBinaryOptionsUD(
params.targetContract
);
QueuedTrade memory queuedTrade = queuedTrades[
optionIdMapping[params.targetContract][params.optionId]
];
address owner = optionsContract.ownerOf(params.optionId);
(, , , , , , , uint256 createdAt, ) = optionsContract.options(
params.optionId
);
if (closeParam.register.shouldRegister) {
try
accountRegistrar.registerAccount(
closeParam.register.oneCT,
owner,
closeParam.register.signature
)
{} catch Error(string memory reason) {
emit FailUnlock(
params.optionId,
params.targetContract,
reason
);
continue;
}
}
if (
!queuedTrade.isEarlyCloseAllowed ||
(block.timestamp - createdAt <
IOptionsConfigUD(optionsContract.config())
.earlyCloseThreshold())
) {
emit FailUnlock(
params.optionId,
params.targetContract,
"Router: Early close is not allowed"
);
continue;
}
(address signer, ) = getAccountMapping(queuedTrade.user);
bool isUserSignValid = Validator.verifyCloseAnytime(
optionsContract.assetPair(),
closeParam.userSignInfo.timestamp,
params.optionId,
closeParam.userSignInfo.signature,
signer
);
if (!isUserSignValid) {
emit FailUnlock(
params.optionId,
params.targetContract,
"Router: User signature didn't match"
);
continue;
}
uint256 priceAtExpiry = getPrice(
params.closingTime,
params.priceUpdateData,
params.priceIds
);
try
optionsContract.unlock(
params.optionId,
priceAtExpiry,
params.closingTime
)
{} catch Error(string memory reason) {
emit FailUnlock(params.optionId, params.targetContract, reason);
continue;
}
}
}
function executeOptions(
CloseTradeParams[] calldata optionData
) external payable {
_validateKeeper();
uint32 arrayLength = uint32(optionData.length);
for (uint32 i = 0; i < arrayLength; i++) {
CloseTradeParams memory params = optionData[i];
IBufferBinaryOptionsUD optionsContract = IBufferBinaryOptionsUD(
params.targetContract
);
(, , , , , uint256 expiration, , , ) = optionsContract.options(
params.optionId
);
QueuedTrade memory queuedTrade = queuedTrades[
optionIdMapping[params.targetContract][params.optionId]
];
if (expiration > block.timestamp) {
emit FailUnlock(
params.optionId,
params.targetContract,
"Router: Wrong closing time"
);
continue;
}
uint256 priceAtExpiry = getPrice(
expiration,
params.priceUpdateData,
params.priceIds
);
try
optionsContract.unlock(
params.optionId,
priceAtExpiry,
expiration
)
{} catch Error(string memory reason) {
emit FailUnlock(params.optionId, params.targetContract, reason);
continue;
}
}
}
function getPrice(
uint256 timestamp,
bytes[] memory priceUpdateData,
bytes32[] memory priceId
) public returns (uint256) {
IPyth.PriceFeed[] memory prices = pyth.parsePriceFeedUpdates{
value: pyth.getUpdateFee(priceUpdateData)
}(
priceUpdateData,
priceId,
uint64(timestamp),
uint64(timestamp + MAXIMUM_PRICE_DELAY_FOR_RESOLVING)
);
IPyth.Price memory price = prices[0].price;
require(price.price > 0, "invalid price");
return uint256(int256(price.price));
}
function _validateKeeper() private view {
require(isKeeper[msg.sender], "Keeper: forbidden");
}
function getAccountMapping(
address user
) public view returns (address, uint256) {
(address oneCT, uint256 nonce) = accountRegistrar.accountMapping(user);
return (oneCT, nonce);
}
function getSafeStrike(
uint256 strike,
bool isAbove,
uint256 spread
) public view returns (uint256) {
return
isAbove
? (strike * (1e8 + spread)) / 1e8
: (strike * (1e8 - spread)) / 1e8;
}
function verifyTrade(
TradeParams memory params,
address user,
address tradeSigner,
IBufferBinaryOptionsUD optionsContract
) internal view returns (bool, string memory) {
SignInfo memory userSignInfo = params.userSignInfo;
if (!contractRegistry[params.targetContract]) {
return (false, "Router: Unauthorized contract");
}
if (queuedTrades[params.queueId].isTradeResolved) {
return (false, "Router: Trade has already been opened");
}
if (prevSignature[userSignInfo.signature]) {
return (false, "Router: Signature already used");
}
if (!Validator.verifyUserTradeParamsUD(params, user, tradeSigner)) {
return (false, "Router: User signature didn't match");
}
if (!params.limitOrder.isLimitOrder) {
if (
block.timestamp - userSignInfo.timestamp >
MAX_DELAY_FOR_OPEN_TRADE
) {
return (false, "Router: Invalid user signature timestamp");
}
if (params.settlementFee != params.userSignedSettlementFee) {
return (false, "Router: Settlement fee is not valid");
}
} else {
if (params.settlementFee > params.userSignedSettlementFee) {
return (false, "Router: Settlement fee is not valid");
}
}
return (true, "");
}
function _verifySigners(
ResolveParams memory params,
QueuedTrade memory queuedTrade,
IBufferBinaryOptionsUD optionsContract,
uint256 safeStrike
) internal view returns (bool, string memory) {
SignInfo memory settlementFeeSignInfo = params.settlementFeeSignInfo;
SignInfo memory spreadSignInfo = params.spreadSignInfo;
if (
!Validator.verifySettlementFee(
optionsContract.assetPair(),
params.settlementFee,
settlementFeeSignInfo.timestamp,
settlementFeeSignInfo.signature,
sfPublisher
)
) {
return (false, "Router: Wrong settlement fee");
}
if (
!Validator.verifySpread(
optionsContract.assetPair(),
params.spread,
spreadSignInfo.timestamp,
spreadSignInfo.signature,
spreadPublisher
)
) {
return (false, "Router: Wrong spread");
}
if (settlementFeeSignInfo.timestamp < block.timestamp) {
return (false, "Router: Settlement fee has expired");
}
if (spreadSignInfo.timestamp < block.timestamp) {
return (false, "Router: Spread has expired");
}
if (
!optionsContract.isStrikeValid(
queuedTrade.slippage,
safeStrike,
queuedTrade.strike
)
) {
return (false, "Router: Slippage limit exceeded");
}
return (true, "");
}
function resolveTrade(
uint256 queueId,
ResolveParams memory params
) public payable {
_validateKeeper();
if (queuedTrades[queueId].isTradeResolved) {
emit FailResolve(queueId, "Router: Trade has already been opened");
return;
}
QueuedTrade memory queuedTrade = queuedTrades[queueId];
IBufferBinaryOptionsUD optionsContract = IBufferBinaryOptionsUD(
queuedTrade.targetContract
);
LimitOrder memory limitOrder = queuedTrade.limitOrder;
if (
limitOrder.isLimitOrder &&
block.timestamp > limitOrder.limitOrderExpiry
) {
emit FailResolve(
queueId,
"Router: Limit order has already expired"
);
return;
}
if (
!limitOrder.isLimitOrder &&
block.timestamp - queuedTrade.queueTime > MAX_DELAY_FOR_OPEN_TRADE
) {
emit FailResolve(queueId, "Router: Wait time too high");
return;
}
uint256 safeStrike = getSafeStrike(
getPrice(
limitOrder.isLimitOrder
? params.limitOrderOpenTime
: queuedTrade.queueTime,
params.priceUpdateData,
params.priceIds
),
queuedTrade.isAbove,
params.spread
);
(bool isValid, string memory errorResaon) = _verifySigners(
params,
queuedTrade,
optionsContract,
safeStrike
);
if (!isValid) {
emit FailResolve(queueId, errorResaon);
return;
}
uint256 amount;
uint256 revisedFee;
IBufferBinaryOptionsUD.OptionParams
memory optionParams = IBufferBinaryOptionsUD.OptionParams(
safeStrike,
0,
queuedTrade.period,
queuedTrade.allowPartialFill,
queuedTrade.totalFee,
queuedTrade.user,
queuedTrade.referralCode,
queuedTrade.settlementFee,
queuedTrade.isAbove
);
try
optionsContract.evaluateParams(optionParams, queuedTrade.slippage)
returns (uint256 _amount, uint256 _revisedFee) {
(amount, revisedFee) = (_amount, _revisedFee);
} catch Error(string memory reason) {
emit CancelTrade(queuedTrade.user, queueId, reason);
return;
}
ERC20 tokenX = ERC20(optionsContract.tokenX());
tokenX.safeTransferFrom(
queuedTrade.user,
queuedTrade.targetContract,
revisedFee
);
optionParams.strike = safeStrike;
optionParams.amount = amount;
optionParams.totalFee = revisedFee;
uint256 optionId = optionsContract.createFromRouter(
optionParams,
limitOrder.isLimitOrder
? params.limitOrderOpenTime
: queuedTrade.queueTime
);
queuedTrades[queueId].isTradeResolved = true;
queueIdInfo[queueId] = QueueIdInfo({
optionId: optionId,
targetContract: queuedTrade.targetContract
});
optionIdMapping[queuedTrade.targetContract][optionId] = queueId;
emit OpenTrade(
queuedTrade.user,
queueId,
optionId,
queuedTrade.targetContract
);
}
function adminWithdraw() external {
require(msg.sender == admin, "Only admin can withdraw");
payable(admin).transfer(address(this).balance);
}
}
文件 4 的 21:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 5 的 21:ECDSA.sol
pragma solidity ^0.8.0;
import "Strings.sol";
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return;
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
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);
}
}
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
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) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
文件 6 的 21:ERC165.sol
pragma solidity ^0.8.0;
import "IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 7 的 21:ERC20.sol
pragma solidity ^0.8.0;
import "IERC20.sol";
import "IERC20Metadata.sol";
import "Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 8 的 21:IAccessControl.sol
pragma solidity ^0.8.0;
interface IAccessControl {
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 9 的 21:IERC1271.sol
pragma solidity ^0.8.0;
interface IERC1271 {
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}
文件 10 的 21:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 11 的 21:IERC20.sol
pragma solidity ^0.8.0;
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 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 12 的 21:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "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);
}
文件 13 的 21:Interfaces.sol
import "ERC20.sol";
pragma solidity 0.8.4;
interface IBufferBinaryOptionPauserV2_5 {
function isPaused() external view returns (bool);
function setIsPaused() external;
}
interface IBufferBinaryOptionPauserV2 {
function isPaused() external view returns (bool);
function toggleCreation() external;
}
interface ICircuitBreaker {
struct MarketPoolPair {
address market;
address pool;
}
struct Configs {
int256 value;
address contractAddress;
}
struct OverallStats {
address contractAddress;
int256 loss;
int256 sf;
int256 lp_sf;
int256 net_loss;
}
struct MarketStats {
address pool;
int256 loss;
int256 sf;
}
struct PoolStats {
address[] markets;
int256 loss;
int256 sf;
}
function update(int256 loss, int256 sf, uint256 option_id) external;
event Update(
int256 loss,
int256 sf,
address market,
address pool,
uint256 option_id
);
event MarketPaused(address market, address pool);
event PoolPaused(address pool);
}
interface IBooster {
struct UserBoostTrades {
uint256 totalBoostTrades;
uint256 totalBoostTradesUsed;
}
function getUserBoostData(
address user,
address token
) external view returns (UserBoostTrades memory);
function updateUserBoost(address user, address token) external;
function getBoostPercentage(
address user,
address token
) external view returns (uint256);
struct Permit {
uint256 value;
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
bool shouldApprove;
}
event ApproveTokenX(
address user,
uint256 nonce,
uint256 value,
uint256 deadline,
address tokenX
);
event BuyCoupon(address indexed token, address indexed user, uint256 price);
event SetPrice(uint256 couponPrice);
event SetBoostPercentage(uint256 boost);
event UpdateBoostTradesUser(address indexed user, address indexed token);
event Configure(uint8[4] nftTierDiscounts);
}
interface IAccountRegistrar {
struct AccountMapping {
address oneCT;
uint256 nonce;
}
event RegisterAccount(
address indexed user,
address indexed oneCT,
uint256 nonce
);
event DeregisterAccount(address indexed account, uint256 nonce);
function accountMapping(
address
) external view returns (address oneCT, uint256 nonce);
function registerAccount(
address oneCT,
address user,
bytes memory signature
) external;
}
interface ILiquidityPool {
struct LockedAmount {
uint256 timestamp;
uint256 amount;
}
struct ProvidedLiquidity {
uint256 unlockedAmount;
LockedAmount[] lockedAmounts;
uint256 nextIndexForUnlock;
}
struct LockedLiquidity {
uint256 amount;
uint256 premium;
bool locked;
}
event Profit(uint256 indexed id, uint256 amount);
event Loss(uint256 indexed id, uint256 amount);
event Provide(address indexed account, uint256 amount, uint256 writeAmount);
event UpdateMaxLiquidity(uint256 indexed maxLiquidity);
event Withdraw(
address indexed account,
uint256 amount,
uint256 writeAmount
);
function unlock(uint256 id) external;
function totalTokenXBalance() external view returns (uint256 amount);
function availableBalance() external view returns (uint256 balance);
function send(uint256 id, address account, uint256 amount) external;
function lock(uint256 id, uint256 tokenXAmount, uint256 premium) external;
}
interface ITraderNFT {
function tokenOwner(uint256 id) external view returns (address user);
function tokenTierMappings(uint256 id) external view returns (uint8 tier);
event UpdateTiers(uint256[] tokenIds, uint8[] tiers, uint256[] batchIds);
}
interface IFakeTraderNFT {
function tokenOwner(uint256 id) external view returns (address user);
function tokenTierMappings(uint256 id) external view returns (uint8 tier);
event UpdateNftBasePrice(uint256 nftBasePrice);
event UpdateMaxNFTMintLimits(uint256 maxNFTMintLimit);
event UpdateBaseURI(string baseURI);
event Claim(address indexed account, uint256 claimTokenId);
event Mint(address indexed account, uint256 tokenId, uint8 tier);
}
interface IReferralStorage {
function codeOwner(string memory _code) external view returns (address);
function traderReferralCodes(address) external view returns (string memory);
function getTraderReferralInfo(
address user
) external view returns (string memory, address);
function setTraderReferralCode(address user, string memory _code) external;
function setReferrerTier(address, uint8) external;
function referrerTierStep(
uint8 referralTier
) external view returns (uint8 step);
function referrerTierDiscount(
uint8 referralTier
) external view returns (uint32 discount);
function referrerTier(address referrer) external view returns (uint8 tier);
struct ReferrerData {
uint256 tradeVolume;
uint256 rebate;
uint256 trades;
}
struct ReferreeData {
uint256 tradeVolume;
uint256 rebate;
}
struct ReferralData {
ReferrerData referrerData;
ReferreeData referreeData;
}
struct Tier {
uint256 totalRebate;
uint256 discountShare;
}
event UpdateTraderReferralCode(address indexed account, string code);
event UpdateReferrerTier(address referrer, uint8 tierId);
event RegisterCode(address indexed account, string code);
event SetCodeOwner(
address indexed account,
address newAccount,
string code
);
}
interface IOptionStorage {
function save(
uint256 optionId,
address optionsContract,
address user
) external;
}
interface ICreationWindowContract {
function isInCreationWindow(uint256 period) external view returns (bool);
}
interface IPyth {
function getValidTimePeriod() external view returns (uint validTimePeriod);
function getPrice(bytes32 id) external view returns (Price memory price);
function getEmaPrice(bytes32 id) external view returns (Price memory price);
function getPriceUnsafe(
bytes32 id
) external view returns (Price memory price);
function getPriceNoOlderThan(
bytes32 id,
uint age
) external view returns (Price memory price);
function getEmaPriceUnsafe(
bytes32 id
) external view returns (Price memory price);
function getEmaPriceNoOlderThan(
bytes32 id,
uint age
) external view returns (Price memory price);
function updatePriceFeeds(bytes[] calldata updateData) external payable;
function updatePriceFeedsIfNecessary(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64[] calldata publishTimes
) external payable;
function getUpdateFee(
bytes[] calldata updateData
) external view returns (uint feeAmount);
function parsePriceFeedUpdates(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64 minPublishTime,
uint64 maxPublishTime
) external payable returns (PriceFeed[] memory priceFeeds);
struct Price {
int64 price;
uint64 conf;
int32 expo;
uint publishTime;
}
struct PriceFeed {
bytes32 id;
Price price;
Price emaPrice;
}
}
interface IIncentivePool {
event Withdrawal(address indexed token, address to, uint256 amount);
event JackpotTriggered(
address indexed userAddress,
uint256 jackpotWinAmount,
address indexed optionContract,
uint256 amount,
address indexed router,
uint256 optionId
);
event UpdateIncentivePoolPercentForJackpot(
uint256 _incentivePoolPercentForJackpot
);
event UpdateMinBetSizeForJackpot(
address indexed token,
uint256 _minBetSizeForJackpot
);
event UpdateMaxJackpotWinPercentForUser(
uint256 _maxJackpotWinPercentForUser
);
event UpdateIncentivePercentForWager(uint256 _incentivePercentForWager);
event UpdateMinWinningsForTransfer(
address indexed token,
uint256 _minWinningsForTransfer
);
event UpdateJackpotToken(address indexed token);
event UpdateKeyHash(bytes32 keyHash);
function executeIncentives(
address userAddress,
uint256 amount,
address optionContract,
uint256 optionId,
address router,
address tokenAddress
) external returns (uint256 jackpotWinAmount);
function minBetSizeForJackpot(address) external view returns (uint256);
function jackpotToken() external view returns (address);
}
文件 14 的 21:InterfacesAB.sol
import "ERC20.sol";
import "Interfaces.sol";
pragma solidity 0.8.4;
interface IApprovals {
struct Permit {
uint256 value;
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
bool shouldApprove;
}
struct RevokeParams {
address tokenX;
address user;
Permit permit;
}
event FailRevoke(address indexed user, address tokenX, string reason);
event ApproveRouter(
address user,
uint256 nonce,
uint256 value,
uint256 deadline,
address tokenX
);
event RevokeRouter(
address user,
uint256 nonce,
uint256 value,
uint256 deadline,
address tokenX
);
}
interface IBufferRouterAB is IApprovals {
struct QueuedTrade {
address user;
address targetContract;
uint128 strike;
uint32 expiration;
uint256 contracts;
bool allowPartialFill;
bool isQueued;
uint256 optionId;
bool isAbove;
uint32 queueTimestamp;
uint256 maxFeePerContract;
string referralCode;
uint256 totalFee;
}
struct OptionInfo {
uint256 queueId;
address signer;
uint256 nonce;
}
struct Register {
address oneCT;
bytes signature;
bool shouldRegister;
}
struct SignInfo {
bytes signature;
uint32 timestamp;
}
struct TradeInitiationParamas {
address targetContract;
bool allowPartialFill;
string referralCode;
bool isAbove;
uint256 totalFee;
uint128 strike;
uint32 expiration;
uint256 maxFeePerContract;
}
struct ResolveTradeParams {
uint256 iv;
uint256 sf;
SignInfo publisherSignInfo;
SignInfo sfSignInfo;
bytes[] priceUpdateData;
bytes32[] priceIds;
}
struct TradeInitiationParamsV2 {
uint256 queueId;
uint32 queueTimestamp;
TradeInitiationParamas tradeInitiationParamas;
SignInfo userSignInfo;
Register register;
Permit permit;
address user;
ResolveTradeParams resolveTradeParams;
}
struct CloseTradeParams {
uint256 optionId;
address targetContract;
bytes[] priceUpdateData;
bytes32[] priceIds;
}
struct IdMapping {
uint256 id;
bool isSet;
}
event OpenTrade(
address indexed user,
uint256 indexed queueId,
uint256 indexed optionId,
address targetContract
);
event CancelTrade(
address indexed account,
uint256 queueId,
string reason,
address targetContract
);
event FailUnlock(
uint256 indexed optionId,
address targetContract,
string reason
);
event FailResolve(uint256 indexed queueId, string reason);
event ContractRegistryUpdated(address targetContract, bool register);
event InitiateTrade(
address indexed user,
uint256 queueId,
uint256 timestamp,
address targetContract,
bool isAbove,
uint128 strike,
uint256 contracts,
uint32 expiration,
uint256 maxFeePerContract
);
}
interface IBufferBinaryOptionsAB {
event Create(
address indexed account,
uint256 indexed id,
uint256 settlementFee,
uint256 totalFee,
int256 skew,
bytes32 marketId,
uint256 amount
);
event CreateMarket(
uint128 strike,
uint32 expiration,
bytes32 marketId,
address optionsContract
);
event Exercise(
address indexed account,
uint256 indexed id,
uint256 profit,
uint256 priceAtExpiration,
bool isAbove
);
event Expire(
uint256 indexed id,
uint256 premium,
uint256 priceAtExpiration,
bool isAbove
);
event Pause(bool isPaused);
event UpdateReferral(
address user,
address referrer,
bool isReferralValid,
uint256 totalFee,
uint256 referrerFee,
uint256 rebate,
string referralCode
);
event LpProfit(uint256 indexed id, uint256 amount);
event LpLoss(uint256 indexed id, uint256 amount);
function createFromRouter(
OptionParams calldata optionParams,
uint32 queueTimestamp
) external returns (uint256 optionID);
function evaluateParams(
OptionParams calldata optionParams
) external view returns (RevisedData memory revisedData);
function tokenX() external view returns (ERC20);
function pool() external view returns (ILiquidityPool);
function config() external view returns (IOptionsConfigAB);
function token0() external view returns (string memory);
function token1() external view returns (string memory);
function ownerOf(uint256 id) external view returns (address);
function assetPair() external view returns (string memory);
function totalMarketOI() external view returns (uint256);
enum State {
Inactive,
Active,
Exercised,
Expired
}
enum AssetCategory {
Forex,
Crypto,
Commodities
}
struct OptionExpiryData {
uint256 optionId;
uint256 priceAtExpiration;
}
event CreateOptionsContract(
address config,
address pool,
address tokenX,
string token0,
string token1,
AssetCategory category
);
struct Option {
State state;
uint128 strike;
uint256 amount;
uint256 lockedAmount;
uint256 premium;
uint32 expiration;
uint256 totalFee;
uint32 createdAt;
bool isAbove;
}
struct OptionParams {
address user;
uint256 sf;
uint256 iv;
bool allowPartialFill;
bool isAbove;
uint256 contracts;
uint128 strike;
uint32 expiration;
uint256 amount;
uint256 totalFee;
uint256 maxFeePerContract;
uint256 currentPrice;
string referralCode;
}
struct RevisedData {
uint256 amount;
uint256 fee;
uint256 revisedContracts;
uint256 revisedSf;
}
function options(
uint256 optionId
)
external
view
returns (
State state,
uint128 strike,
uint256 amount,
uint256 lockedAmount,
uint256 premium,
uint32 expiration,
uint256 totalFee,
uint32 createdAt,
bool isAbove
);
function unlock(uint256 optionID, uint256 closingPrice) external;
function runInitialChecks(uint128 strike, uint32 expiration) external;
}
interface IOptionsConfigAB {
event UpdateSettlementFeeDisbursalContract(address value);
event UpdatetraderNFTContract(address value);
event UpdateOptionStorageContract(address value);
event UpdateCreationWindowContract(address value);
event UpdatePlatformFee(uint256 _platformFee);
event UpdateIV(uint32 _iv);
event UpdateMaxSkew(int256 _maxSkew);
event UpdateCircuitBreakerContract(address _circuitBreakerContract);
event UpdateSf(uint256 sf);
event UpdatePayout(uint256 payout);
event UpdateStrikeStepSize(uint128 strikeStepSize);
function maxSkew() external view returns (int256);
function circuitBreakerContract() external view returns (address);
function settlementFeeDisbursalContract() external view returns (address);
function platformFee() external view returns (uint256);
function payout() external view returns (uint256);
function optionStorageContract() external view returns (address);
function creationWindowContract() external view returns (address);
function strikeStepSize() external view returns (uint128);
}
文件 15 的 21:InterfacesUD.sol
import "ERC20.sol";
import "Interfaces.sol";
pragma solidity 0.8.4;
interface IBufferRouterUD {
struct QueuedTrade {
address user;
uint256 totalFee;
uint256 period;
address targetContract;
uint256 strike;
uint256 slippage;
bool allowPartialFill;
string referralCode;
uint256 settlementFee;
LimitOrder limitOrder;
bool isTradeResolved;
bool isEarlyCloseAllowed;
bool isAbove;
uint256 queueTime;
}
struct QueueIdInfo {
address targetContract;
uint256 optionId;
}
struct OptionInfo {
uint256 queueId;
address signer;
uint256 nonce;
}
struct SignInfo {
bytes signature;
uint256 timestamp;
}
struct LimitOrder {
bool isLimitOrder;
uint256 limitOrderExpiry;
uint256 limitOrderOpenTime;
}
struct TradeParams {
uint256 queueId;
uint256 totalFee;
uint256 period;
address targetContract;
uint256 strike;
uint256 slippage;
bool allowPartialFill;
string referralCode;
bool isAbove;
uint256 settlementFee;
LimitOrder limitOrder;
uint256 userSignedSettlementFee;
uint256 spread;
uint256 queueTime;
SignInfo settlementFeeSignInfo;
SignInfo userSignInfo;
bytes[] priceUpdateData;
bytes32[] priceIds;
SignInfo spreadSignInfo;
}
struct TradeParamsV2 {
uint256 totalFee;
uint256 period;
address targetContract;
uint256 strike;
uint256 slippage;
bool allowPartialFill;
string referralCode;
bool isAbove;
uint256 settlementFee;
LimitOrder limitOrder;
}
struct ResolveParams {
uint256 settlementFee;
uint256 spread;
SignInfo settlementFeeSignInfo;
bytes[] priceUpdateData;
bytes32[] priceIds;
SignInfo spreadSignInfo;
uint256 limitOrderOpenTime;
}
struct Register {
address oneCT;
bytes signature;
bool shouldRegister;
}
struct Permit {
uint256 value;
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
bool shouldApprove;
}
struct RevokeParams {
address tokenX;
address user;
Permit permit;
}
struct OpenTxn {
TradeParams tradeParams;
Register register;
Permit permit;
address user;
}
struct AccountMapping {
address oneCT;
uint256 nonce;
}
struct CloseTradeParams {
uint256 optionId;
address targetContract;
uint256 closingTime;
bytes[] priceUpdateData;
bytes32[] priceIds;
}
struct CloseAnytimeParams {
CloseTradeParams closeTradeParams;
Register register;
SignInfo userSignInfo;
}
struct IdMapping {
uint256 id;
bool isSet;
}
event OpenTrade(
address indexed account,
uint256 queueId,
uint256 optionId,
address targetContract
);
event CancelTrade(address indexed account, uint256 queueId, string reason);
event FailUnlock(
uint256 indexed optionId,
address targetContract,
string reason
);
event FailResolve(uint256 indexed queueId, string reason);
event FailRevoke(address indexed user, address tokenX, string reason);
event ContractRegistryUpdated(address targetContract, bool register);
event ApproveRouter(
address user,
uint256 nonce,
uint256 value,
uint256 deadline,
address tokenX
);
event RevokeRouter(
address user,
uint256 nonce,
uint256 value,
uint256 deadline,
address tokenX
);
event InitiateTrade(
address indexed user,
uint256 queueId,
address targetContract,
uint256 strike,
uint256 slippage,
uint256 period,
bool allowPartialFill,
uint256 totalFee,
string referralCode,
uint256 settlementFee,
bool isAbove
);
}
interface IBufferBinaryOptionsUD {
event Create(
address indexed account,
uint256 indexed id,
uint256 settlementFee,
uint256 totalFee
);
event Exercise(
address indexed account,
uint256 indexed id,
uint256 profit,
uint256 priceAtExpiration,
bool isAbove
);
event Expire(
uint256 indexed id,
uint256 premium,
uint256 priceAtExpiration,
bool isAbove
);
event Pause(bool isPaused);
event UpdateReferral(
address user,
address referrer,
bool isReferralValid,
uint256 totalFee,
uint256 referrerFee,
uint256 rebate,
string referralCode
);
event LpProfit(uint256 indexed id, uint256 amount);
event LpLoss(uint256 indexed id, uint256 amount);
function createFromRouter(
OptionParams calldata optionParams,
uint256 queuedTime
) external returns (uint256 optionID);
function evaluateParams(
OptionParams calldata optionParams,
uint256 slippage
) external returns (uint256 amount, uint256 revisedFee);
function tokenX() external view returns (ERC20);
function pool() external view returns (ILiquidityPool);
function config() external view returns (IOptionsConfigUD);
function token0() external view returns (string memory);
function token1() external view returns (string memory);
function ownerOf(uint256 id) external view returns (address);
function assetPair() external view returns (string memory);
function totalMarketOI() external view returns (uint256);
function getMaxOI() external view returns (uint256);
function fees(
uint256 amount,
address user,
string calldata referralCode,
uint256 baseSettlementFeePercent
)
external
view
returns (uint256 total, uint256 settlementFee, uint256 premium);
function isStrikeValid(
uint256 slippage,
uint256 currentPrice,
uint256 strike
) external pure returns (bool);
enum State {
Inactive,
Active,
Exercised,
Expired
}
enum AssetCategory {
Forex,
Crypto,
Commodities
}
struct OptionExpiryData {
uint256 optionId;
uint256 priceAtExpiration;
}
event CreateOptionsContract(
address config,
address pool,
address tokenX,
string token0,
string token1,
AssetCategory category
);
struct Option {
State state;
uint256 strike;
uint256 amount;
uint256 lockedAmount;
uint256 premium;
uint256 expiration;
uint256 totalFee;
uint256 createdAt;
bool isAbove;
}
struct OptionParams {
uint256 strike;
uint256 amount;
uint256 period;
bool allowPartialFill;
uint256 totalFee;
address user;
string referralCode;
uint256 baseSettlementFeePercentage;
bool isAbove;
}
function options(
uint256 optionId
)
external
view
returns (
State state,
uint256 strike,
uint256 amount,
uint256 lockedAmount,
uint256 premium,
uint256 expiration,
uint256 totalFee,
uint256 createdAt,
bool isAbove
);
function unlock(
uint256 optionID,
uint256 priceAtExpiration,
uint256 closingTime
) external;
}
interface IOptionsConfigUD {
event UpdateMaxPeriod(uint32 value);
event UpdateMinPeriod(uint32 value);
event UpdateEarlyCloseThreshold(uint32 earlyCloseThreshold);
event UpdateEarlyClose(bool isAllowed);
event UpdateSettlementFeeDisbursalContract(address value);
event UpdatetraderNFTContract(address value);
event UpdateMinFee(uint256 value);
event UpdateOptionStorageContract(address value);
event UpdateCreationWindowContract(address value);
event UpdatePlatformFee(uint256 _platformFee);
event UpdatePoolOIStorageContract(address _poolOIStorageContract);
event UpdatePoolOIConfigContract(address _poolOIConfigContract);
event UpdateMarketOIConfigContract(address _marketOIConfigContract);
event UpdateIV(uint32 _iv);
event UpdateBoosterContract(address _boosterContract);
event UpdateSpreadConfig1(uint256 spreadConfig1);
event UpdateSpreadConfig2(uint256 spreadConfig2);
event UpdateIVFactorITM(uint256 ivFactorITM);
event UpdateIVFactorOTM(uint256 ivFactorOTM);
event UpdateSpreadFactor(uint32 ivFactorOTM);
event UpdateCircuitBreakerContract(address _circuitBreakerContract);
function circuitBreakerContract() external view returns (address);
function settlementFeeDisbursalContract() external view returns (address);
function maxPeriod() external view returns (uint32);
function minPeriod() external view returns (uint32);
function minFee() external view returns (uint256);
function platformFee() external view returns (uint256);
function optionStorageContract() external view returns (address);
function creationWindowContract() external view returns (address);
function poolOIStorageContract() external view returns (address);
function poolOIConfigContract() external view returns (address);
function marketOIConfigContract() external view returns (address);
function iv() external view returns (uint32);
function earlyCloseThreshold() external view returns (uint32);
function isEarlyCloseAllowed() external view returns (bool);
function boosterContract() external view returns (address);
function spreadConfig1() external view returns (uint256);
function spreadConfig2() external view returns (uint256);
function spreadFactor() external view returns (uint32);
function getFactoredIv(bool isITM) external view returns (uint32);
}
interface IPoolOIStorage {
function updatePoolOI(bool isIncreased, uint256 interest) external;
function totalPoolOI() external view returns (uint256);
}
interface IPoolOIConfig {
function getMaxPoolOI() external view returns (uint256);
function getPoolOICap() external view returns (uint256);
}
interface IMarketOIConfig {
function getMaxMarketOI(
uint256 currentMarketOI
) external view returns (uint256);
function getMarketOICap() external view returns (uint256);
}
文件 16 的 21:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 17 的 21:SafeERC20.sol
pragma solidity ^0.8.0;
import "IERC20.sol";
import "draft-IERC20Permit.sol";
import "Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 18 的 21:SignatureChecker.sol
pragma solidity ^0.8.0;
import "ECDSA.sol";
import "Address.sol";
import "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);
if (error == ECDSA.RecoverError.NoError && recovered == signer) {
return true;
}
(bool success, bytes memory result) = signer.staticcall(
abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
);
return (success &&
result.length == 32 &&
abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
}
}
文件 19 的 21:Strings.sol
pragma solidity ^0.8.0;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
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_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
文件 20 的 21:Validator.sol
pragma solidity 0.8.4;
import "ECDSA.sol";
import "SignatureChecker.sol";
import "InterfacesUD.sol";
import "InterfacesAB.sol";
library Validator {
struct EIP712Domain {
string name;
string version;
uint256 chainId;
address verifyingContract;
}
function domainSperator() internal view returns (bytes32) {
return
keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
),
keccak256(bytes("Validator")),
keccak256(bytes("1")),
block.chainid,
address(this)
)
);
}
function _validate(
bytes32 hashData,
bytes memory expectedSignature,
address expectedSigner
) internal view returns (bool) {
bytes32 digest = keccak256(
abi.encodePacked("\x19\x01", domainSperator(), hashData)
);
return
SignatureChecker.isValidSignatureNow(
expectedSigner,
digest,
expectedSignature
);
}
function verifyUserTradeParamsUD(
IBufferRouterUD.TradeParams memory params,
address user,
address signer
) internal view returns (bool) {
bytes32 hashData = keccak256(
abi.encode(
keccak256(
"UserTradeSignatureWithSettlementFee(address user,uint256 totalFee,uint256 period,address targetContract,uint256 strike,uint256 slippage,bool allowPartialFill,string referralCode,uint256 timestamp,uint256 settlementFee,bool isAbove)"
),
user,
params.totalFee,
params.period,
params.targetContract,
params.strike,
params.slippage,
params.allowPartialFill,
keccak256(bytes(params.referralCode)),
params.userSignInfo.timestamp,
params.userSignedSettlementFee,
params.isAbove
)
);
return _validate(hashData, params.userSignInfo.signature, signer);
}
function verifyUserTradeParamsAB(
IBufferRouterAB.TradeInitiationParamas memory params,
address user,
address signer,
IBufferRouterAB.SignInfo memory userSignInfo
) internal view returns (bool) {
bytes32 hashData = keccak256(
abi.encode(
keccak256(
"UserTradeSignature(address user,address targetContract,uint32 expiration,uint256 totalFee,uint256 strike,bool isAbove,uint256 maxFeePerContract,bool allowPartialFill,string referralCode,uint256 timestamp)"
),
user,
params.targetContract,
params.expiration,
params.totalFee,
params.strike,
params.isAbove,
params.maxFeePerContract,
params.allowPartialFill,
keccak256(bytes(params.referralCode)),
userSignInfo.timestamp
)
);
return _validate(hashData, userSignInfo.signature, signer);
}
function verifyCloseAnytime(
string memory assetPair,
uint256 timestamp,
uint256 optionId,
bytes memory signature,
address signer
) internal view returns (bool) {
bytes32 hashData = keccak256(
abi.encode(
keccak256(
"CloseAnytimeSignature(string assetPair,uint256 timestamp,uint256 optionId)"
),
keccak256(bytes(assetPair)),
timestamp,
optionId
)
);
return _validate(hashData, signature, signer);
}
function verifySettlementFee(
string memory assetPair,
uint256 settlementFee,
uint256 expiryTimestamp,
bytes memory signature,
address signer
) internal view returns (bool) {
bytes32 hashData = keccak256(
abi.encode(
keccak256(
"SettlementFeeSignature(string assetPair,uint256 expiryTimestamp,uint256 settlementFee)"
),
keccak256(bytes(assetPair)),
expiryTimestamp,
settlementFee
)
);
return _validate(hashData, signature, signer);
}
function verifySpread(
string memory assetPair,
uint256 spread,
uint256 expiryTimestamp,
bytes memory signature,
address signer
) internal view returns (bool) {
bytes32 hashData = keccak256(
abi.encode(
keccak256(
"SpreadSignature(string assetPair,uint256 expiryTimestamp,uint256 spread)"
),
keccak256(bytes(assetPair)),
expiryTimestamp,
spread
)
);
return _validate(hashData, signature, signer);
}
function verifyUserRegistration(
address oneCT,
address user,
uint256 nonce,
bytes memory signature
) internal view returns (bool) {
bytes32 hashData = keccak256(
abi.encode(
keccak256(
"RegisterAccount(address oneCT,address user,uint256 nonce)"
),
oneCT,
user,
nonce
)
);
return _validate(hashData, signature, user);
}
function verifyUserDeregistration(
address user,
uint256 nonce,
bytes memory signature
) internal view returns (bool) {
bytes32 hashData = keccak256(
abi.encode(
keccak256("DeregisterAccount(address user,uint256 nonce)"),
user,
nonce
)
);
return _validate(hashData, signature, user);
}
function verifyIv(
string memory assetPair,
uint256 timestamp,
uint256 iv,
bytes memory signature,
address signer
) internal view returns (bool) {
bytes32 hashData = keccak256(
abi.encodePacked(assetPair, timestamp, iv)
);
bytes32 digest = ECDSA.toEthSignedMessageHash(hashData);
return SignatureChecker.isValidSignatureNow(signer, digest, signature);
}
}
文件 21 的 21:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
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);
}
{
"compilationTarget": {
"BufferRouter.sol": "BufferRouterUD"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_sfPublisher","type":"address"},{"internalType":"address","name":"_spreadPublisher","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_accountRegistrar","type":"address"},{"internalType":"contract IPyth","name":"_pyth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deadline","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenX","type":"address"}],"name":"ApproveRouter","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"queueId","type":"uint256"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"CancelTrade","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"targetContract","type":"address"},{"indexed":false,"internalType":"bool","name":"register","type":"bool"}],"name":"ContractRegistryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"queueId","type":"uint256"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"FailResolve","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"tokenX","type":"address"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"FailRevoke","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"optionId","type":"uint256"},{"indexed":false,"internalType":"address","name":"targetContract","type":"address"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"FailUnlock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"queueId","type":"uint256"},{"indexed":false,"internalType":"address","name":"targetContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"strike","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"slippage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"period","type":"uint256"},{"indexed":false,"internalType":"bool","name":"allowPartialFill","type":"bool"},{"indexed":false,"internalType":"uint256","name":"totalFee","type":"uint256"},{"indexed":false,"internalType":"string","name":"referralCode","type":"string"},{"indexed":false,"internalType":"uint256","name":"settlementFee","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isAbove","type":"bool"}],"name":"InitiateTrade","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"queueId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"optionId","type":"uint256"},{"indexed":false,"internalType":"address","name":"targetContract","type":"address"}],"name":"OpenTrade","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deadline","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenX","type":"address"}],"name":"RevokeRouter","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAXIMUM_PRICE_DELAY_FOR_RESOLVING","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DELAY_FOR_OPEN_TRADE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUEUE_TIME_LAG","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accountRegistrar","outputs":[{"internalType":"contract IAccountRegistrar","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"adminWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint256","name":"optionId","type":"uint256"},{"internalType":"address","name":"targetContract","type":"address"},{"internalType":"uint256","name":"closingTime","type":"uint256"},{"internalType":"bytes[]","name":"priceUpdateData","type":"bytes[]"},{"internalType":"bytes32[]","name":"priceIds","type":"bytes32[]"}],"internalType":"struct IBufferRouterUD.CloseTradeParams","name":"closeTradeParams","type":"tuple"},{"components":[{"internalType":"address","name":"oneCT","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bool","name":"shouldRegister","type":"bool"}],"internalType":"struct IBufferRouterUD.Register","name":"register","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"internalType":"struct IBufferRouterUD.SignInfo","name":"userSignInfo","type":"tuple"}],"internalType":"struct IBufferRouterUD.CloseAnytimeParams[]","name":"closeParams","type":"tuple[]"}],"name":"closeAnytime","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"contractRegistry","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"optionId","type":"uint256"},{"internalType":"address","name":"targetContract","type":"address"},{"internalType":"uint256","name":"closingTime","type":"uint256"},{"internalType":"bytes[]","name":"priceUpdateData","type":"bytes[]"},{"internalType":"bytes32[]","name":"priceIds","type":"bytes32[]"}],"internalType":"struct IBufferRouterUD.CloseTradeParams[]","name":"optionData","type":"tuple[]"}],"name":"executeOptions","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getAccountMapping","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes[]","name":"priceUpdateData","type":"bytes[]"},{"internalType":"bytes32[]","name":"priceId","type":"bytes32[]"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"strike","type":"uint256"},{"internalType":"bool","name":"isAbove","type":"bool"},{"internalType":"uint256","name":"spread","type":"uint256"}],"name":"getSafeStrike","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"totalFee","type":"uint256"},{"internalType":"uint256","name":"period","type":"uint256"},{"internalType":"address","name":"targetContract","type":"address"},{"internalType":"uint256","name":"strike","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"bool","name":"allowPartialFill","type":"bool"},{"internalType":"string","name":"referralCode","type":"string"},{"internalType":"bool","name":"isAbove","type":"bool"},{"internalType":"uint256","name":"settlementFee","type":"uint256"},{"components":[{"internalType":"bool","name":"isLimitOrder","type":"bool"},{"internalType":"uint256","name":"limitOrderExpiry","type":"uint256"},{"internalType":"uint256","name":"limitOrderOpenTime","type":"uint256"}],"internalType":"struct IBufferRouterUD.LimitOrder","name":"limitOrder","type":"tuple"}],"internalType":"struct IBufferRouterUD.TradeParamsV2","name":"params","type":"tuple"}],"name":"initiateTrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isKeeper","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastSavedQueueId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint256","name":"queueId","type":"uint256"},{"internalType":"uint256","name":"totalFee","type":"uint256"},{"internalType":"uint256","name":"period","type":"uint256"},{"internalType":"address","name":"targetContract","type":"address"},{"internalType":"uint256","name":"strike","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"bool","name":"allowPartialFill","type":"bool"},{"internalType":"string","name":"referralCode","type":"string"},{"internalType":"bool","name":"isAbove","type":"bool"},{"internalType":"uint256","name":"settlementFee","type":"uint256"},{"components":[{"internalType":"bool","name":"isLimitOrder","type":"bool"},{"internalType":"uint256","name":"limitOrderExpiry","type":"uint256"},{"internalType":"uint256","name":"limitOrderOpenTime","type":"uint256"}],"internalType":"struct IBufferRouterUD.LimitOrder","name":"limitOrder","type":"tuple"},{"internalType":"uint256","name":"userSignedSettlementFee","type":"uint256"},{"internalType":"uint256","name":"spread","type":"uint256"},{"internalType":"uint256","name":"queueTime","type":"uint256"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"internalType":"struct IBufferRouterUD.SignInfo","name":"settlementFeeSignInfo","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"internalType":"struct IBufferRouterUD.SignInfo","name":"userSignInfo","type":"tuple"},{"internalType":"bytes[]","name":"priceUpdateData","type":"bytes[]"},{"internalType":"bytes32[]","name":"priceIds","type":"bytes32[]"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"internalType":"struct IBufferRouterUD.SignInfo","name":"spreadSignInfo","type":"tuple"}],"internalType":"struct IBufferRouterUD.TradeParams","name":"tradeParams","type":"tuple"},{"components":[{"internalType":"address","name":"oneCT","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bool","name":"shouldRegister","type":"bool"}],"internalType":"struct IBufferRouterUD.Register","name":"register","type":"tuple"},{"components":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"bool","name":"shouldApprove","type":"bool"}],"internalType":"struct IBufferRouterUD.Permit","name":"permit","type":"tuple"},{"internalType":"address","name":"user","type":"address"}],"internalType":"struct IBufferRouterUD.OpenTxn[]","name":"params","type":"tuple[]"}],"name":"openTrades","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"optionIdMapping","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"prevSignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pyth","outputs":[{"internalType":"contract IPyth","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"queueIdInfo","outputs":[{"internalType":"address","name":"targetContract","type":"address"},{"internalType":"uint256","name":"optionId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"queuedTrades","outputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"totalFee","type":"uint256"},{"internalType":"uint256","name":"period","type":"uint256"},{"internalType":"address","name":"targetContract","type":"address"},{"internalType":"uint256","name":"strike","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"bool","name":"allowPartialFill","type":"bool"},{"internalType":"string","name":"referralCode","type":"string"},{"internalType":"uint256","name":"settlementFee","type":"uint256"},{"components":[{"internalType":"bool","name":"isLimitOrder","type":"bool"},{"internalType":"uint256","name":"limitOrderExpiry","type":"uint256"},{"internalType":"uint256","name":"limitOrderOpenTime","type":"uint256"}],"internalType":"struct IBufferRouterUD.LimitOrder","name":"limitOrder","type":"tuple"},{"internalType":"bool","name":"isTradeResolved","type":"bool"},{"internalType":"bool","name":"isEarlyCloseAllowed","type":"bool"},{"internalType":"bool","name":"isAbove","type":"bool"},{"internalType":"uint256","name":"queueTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"queueId","type":"uint256"},{"components":[{"internalType":"uint256","name":"settlementFee","type":"uint256"},{"internalType":"uint256","name":"spread","type":"uint256"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"internalType":"struct IBufferRouterUD.SignInfo","name":"settlementFeeSignInfo","type":"tuple"},{"internalType":"bytes[]","name":"priceUpdateData","type":"bytes[]"},{"internalType":"bytes32[]","name":"priceIds","type":"bytes32[]"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"internalType":"struct IBufferRouterUD.SignInfo","name":"spreadSignInfo","type":"tuple"},{"internalType":"uint256","name":"limitOrderOpenTime","type":"uint256"}],"internalType":"struct IBufferRouterUD.ResolveParams","name":"params","type":"tuple"}],"name":"resolveTrade","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenX","type":"address"},{"internalType":"address","name":"user","type":"address"},{"components":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"bool","name":"shouldApprove","type":"bool"}],"internalType":"struct IBufferRouterUD.Permit","name":"permit","type":"tuple"}],"internalType":"struct IBufferRouterUD.RevokeParams[]","name":"revokeParams","type":"tuple[]"}],"name":"revokeApprovals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"targetContract","type":"address"},{"internalType":"bool","name":"register","type":"bool"}],"name":"setContractRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"bool","name":"_isActive","type":"bool"}],"name":"setKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sfPublisher","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"spreadPublisher","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]