Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
PerpCrucible
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity >=0.8.19;
import "../../libraries/EnumerableSet.sol";
import "../../libraries/BasicMath.sol";
import "../../interfaces/Errors.sol";
import "../../interfaces/Events.sol";
import "../Crucible.sol";
import "lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol";
// ____ ______ _ __ __
// / __ \___ _________ / ____/______ _______(_) /_ / /__
// / /_/ / _ \/ ___/ __ \/ / / ___/ / / / ___/ / __ \/ / _ \
// / ____/ __/ / / /_/ / /___/ / / /_/ / /__/ / /_/ / / __/
// /_/ \___/_/ / .___/\____/_/ \__,_/\___/_/_.___/_/\___/
// /_/
/////////////////////////////////////////////////////////////////
contract PerpCrucible is Crucible, Initializable {
using EnumerableSet for EnumerableSet.UintSet;
using BasicMath for uint256;
using BasicMath for int256;
// Dynamic State
//////////////////////////////////////
// mapping from product id to subaccount to Position
mapping(uint32 => mapping(address => Structs.PositionState)) public subAccountPositions;
// mapping from productId to current cumulative funding
mapping(uint32 => int256) public currentCumFunding;
function initialize(address _addressManifest) external initializer {
__Crucible_init(_addressManifest);
}
// External - Access Controlled
//////////////////////////////////////
/// @notice this function takes funding diffs as parameters. This is the dollar value of funding incurred per contract in the period
/// @dev only accessible by the order dispatch
/// @param fundingData array of bytes containing details of funding updates for each product id
function updateCumulativeFundings(bytes memory fundingData) external {
// check that the caller is the order dispatch
_isOrderDispatch();
// look at the length of the byte array to determine how many funding rates are being updated
if (fundingData.length % 36 != 0) revert Errors.OrderByteLengthInvalid();
uint256 fundingDataLen = fundingData.length;
for (uint256 i; i < fundingDataLen;) {
uint32 productId;
int256 fundingDiff;
uint256 pidOffset = i + 4;
uint256 fundingOffset = i + 36;
/// @solidity memory-safe-assembly
assembly {
productId := mload(add(fundingData, pidOffset))
fundingDiff := mload(add(fundingData, fundingOffset))
}
currentCumFunding[productId] += fundingDiff;
i += 36;
}
}
/// @notice updates state with details of a user's new position
/// @dev a user can only hold one position for each productID (no concurrent short and long)
/// @param takerSubAccount the subaccount of the taker of the matched order
/// @param makerSubAccount the subaccount of the maker of the matched order
/// @param productId product ID of the market being traded
/// @param makerPosition the position that is being incremented onto the existing position,
/// uses the maker pos as reference and flips the direction for the taker
/// @return takerRealisedPnl the profit or loss of the realised portion of the taker's position, including all funding accrued
/// @return makerRealisedPnl the profit or loss of the realised portion of the maker's position, including all funding accrued
function updatePosition(
address takerSubAccount,
address makerSubAccount,
uint32 productId,
Structs.NewPosition memory makerPosition
) external returns (int256 takerRealisedPnl, int256 makerRealisedPnl) {
// check that the caller is the order dispatch or liquidation
_isBalanceUpdater();
takerRealisedPnl = _updatePosition(
takerSubAccount,
productId,
Structs.NewPosition(
makerPosition.executionPrice, makerPosition.quantity, !makerPosition.isLong
)
);
makerRealisedPnl = _updatePosition(makerSubAccount, productId, makerPosition);
}
// Internal
//////////////////////////////////////
/// @notice updates state with details of a user's new position
/// @dev a user can only hold one position for each productID (no concurrent short and long)
/// @param subAccount the subaccount that the position belongs to
/// @param productId product ID of the market being traded
/// @param position the position that is being incremented onto the existing position
/// @return realisedPnl the profit or loss of the realised portion of the position, including all funding accrued
function _updatePosition(
address subAccount,
uint32 productId,
Structs.NewPosition memory position
) internal returns (int256 realisedPnl) {
Structs.PositionState memory existingPosition = subAccountPositions[productId][subAccount];
if (openPositionIds[subAccount].contains(productId)) {
// position is already open for this market, so update it and settle funding
// settle funding first
// equal to difference in cumulative funding snapshots * number of contracts open
// if cumFunding has increased, longs will have negative funding pnl, and vice versa
realisedPnl = (
existingPosition.isLong
? (existingPosition.initCumFunding - currentCumFunding[productId])
: (currentCumFunding[productId] - existingPosition.initCumFunding)
).mul(int256(existingPosition.quantity));
if (existingPosition.isLong == position.isLong) {
// add to existing position
// update avgEntryPrice and quantity of position
// no pnl is realised here
uint256 newAvgEntryPrice = (
existingPosition.avgEntryPrice.mul(existingPosition.quantity)
+ position.executionPrice.mul(position.quantity)
).div(existingPosition.quantity + position.quantity);
subAccountPositions[productId][subAccount] = Structs.PositionState(
newAvgEntryPrice,
existingPosition.quantity + position.quantity,
position.isLong,
currentCumFunding[productId]
);
} else if (existingPosition.quantity >= position.quantity) {
realisedPnl += (
existingPosition.isLong
? (int256(position.executionPrice) - int256(existingPosition.avgEntryPrice))
: (int256(existingPosition.avgEntryPrice) - int256(position.executionPrice))
).mul(int256(position.quantity));
if (existingPosition.quantity == position.quantity) {
// close position entirely
// realise all pnl and remove position from state
openPositionIds[subAccount].remove(productId);
delete subAccountPositions[productId][subAccount];
} else {
// reduce position size but is not flipping long/short side
// realise pnl proportional to quantity of position being closed
// reduce the position quantity
subAccountPositions[productId][subAccount] = Structs.PositionState(
existingPosition.avgEntryPrice,
existingPosition.quantity - position.quantity,
existingPosition.isLong,
currentCumFunding[productId]
);
}
} else {
// existingPosition.quantity < position.quantity
// position is fully closed and flipped to opposite direction
// realise all pnl
// create new position on opposite long/short side with any leftover size
realisedPnl += (
existingPosition.isLong
? (int256(position.executionPrice) - int256(existingPosition.avgEntryPrice))
: (int256(existingPosition.avgEntryPrice) - int256(position.executionPrice))
).mul(int256(existingPosition.quantity));
subAccountPositions[productId][subAccount] = Structs.PositionState(
position.executionPrice,
position.quantity - existingPosition.quantity,
position.isLong,
currentCumFunding[productId]
);
}
} else {
// no existing position for this asset exists
// add position to storage
subAccountPositions[productId][subAccount] = Structs.PositionState(
position.executionPrice,
position.quantity,
position.isLong,
currentCumFunding[productId]
);
openPositionIds[subAccount].add(productId);
}
emit Events.PerpPositionUpdated(
subAccount, productId, existingPosition, subAccountPositions[productId][subAccount]
);
}
// Basic Getters
//////////////////////////////////////
function getSubAccountPosition(uint32 productId, address subAccount)
external
view
returns (Structs.PositionState memory)
{
return subAccountPositions[productId][subAccount];
}
function isPositionOpenForId(address subAccount, uint32 productId)
external
view
returns (bool)
{
return openPositionIds[subAccount].contains(productId);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.9;
/**
* @notice Library for basic math
*/
library BasicMath {
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev multiplies two e18 notation uint256 together, diving the result by 1e18
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return (a * b) / 1e18;
}
/**
* @dev multiplies two e18 notation ints together, diving the result by 1e18
*/
function mul(int256 a, int256 b) internal pure returns (int256) {
return (a * b) / 1e18;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return (a * 1e18) / b;
}
}// SPDX-License-Identifier: Unlicensed
pragma solidity >=0.8.19;
interface Errors {
// Ciao Errors
///////////////
error NoAssetsToWithdraw();
error BalanceInsufficient();
error DepositQuantityInvalid();
error WithdrawQuantityInvalid();
error SubAccountHasPositions();
// OrderDispatch Errors
////////////////////////
error TxIdInvalid();
error SideInvalid();
error PriceInvalid();
error ProductInvalid();
error OrderCheckFailed();
error SignatureInvalid();
error ProductIdMismatch();
error SubAccountHealthy();
error NoCoreCollateralDebt();
error OrderByteLengthInvalid();
// ProductCatalogue Errors
///////////////////////////
error ProductNotSet();
error ProductIdInvalid();
error BaseAssetInvalid();
error QuoteAssetInvalid();
error ProductAlreadySet();
error MakerRebateFeeInvalid();
// Furnace Errors
///////////////////////////
error InvalidArrayLength();
// AddressManifest Errors
///////////////////////////
error SenderInvalid();
error DigestedAlready();
// Liquidation Errors
///////////////////////////
error LiquidatedTooMuch();
error InvalidLiquidation();
error LiquidatePerpsFirst();
error NoPositionExistsForId();
error AccountNotLiquidatable();
error InvalidLiquidationSize();
error LiquidateNakedPerpsFirst();
error LiquidatorBelowInitialHealth();
error LiquidatorCanNotBeLiquidatee();
error CanNotLiquidateCoreCollateral();
error InvalidLiquidateFeeFractionValue();
}// SPDX-License-Identifier: Unlicensed
pragma solidity >=0.8.19;
import "./Structs.sol";
interface Events {
// Ciao Events
////////////////////////
event Deposit(
address indexed account, uint8 indexed subAccountId, address indexed asset, uint256 quantity
);
event RequestWithdrawal(
address indexed account, uint8 indexed subAccountId, address indexed asset, uint256 quantity
);
event ExecuteWithdrawal(
address indexed account, uint8 indexed subAccountId, address indexed asset, uint256 quantity
);
event BalanceChanged(
address indexed subAccount, address indexed asset, int256 balanceBefore, int256 balanceAfter
);
event InsuranceChanged(address insurance);
event MinDepositAmountChanged(address asset, uint256 minDepositAmount);
event FeeRecipientChanged(address feeRecipient);
event CoreCollateralAddressChanged(address coreCollateralAddress);
event BlastGasRecipientChanged(address blastGasRecipient);
event BlastYieldRecipientChanged(address blastYieldRecipient);
event BlastYieldClaimed(address asset, address recipient, uint256 amount);
// OrderDispatch Events
//////////////////////////////////////
event OrderMatched(bytes32 takerDigest, bytes32 makerDigest);
event TxFeeChanged(uint8 action, uint256 txFee);
// AddressManifest Events
//////////////////////////////////////
event ManifestUpdated(uint256 indexed id, address indexed newAddress);
event SignerApprovalUpdated(
address indexed account,
uint8 indexed subAccountId,
address indexed approvedSigner,
bool isApproved
);
event OperatorUpdated(address operator);
event AdminUpdated(address admin);
// Product Catalogue Events
////////////////////////////
event ProductTradeabilityChanged(uint32 indexed productId, bool isProductTradeable);
event ProductFeesChanged(
uint32 indexed productId, uint256 takerFee, uint256 makerFee, bool isMakerRebate
);
event ProductSet(
uint32 indexed productId,
uint8 indexed productType,
address indexed baseAsset,
address quoteAsset,
uint128 takerFee,
uint128 makerFee,
bool isMakerRebate
);
event BaseAssetQuoteAssetSpotIdSet(
address indexed baseAsset, address indexed quoteAsset, uint32 productId
);
event ProductBaseAssetChanged(uint32 productId, address baseAsset);
// Furnace Events
//////////////////////////////////////
event RiskWeightsSet(
uint32 indexed productId,
uint64 initialLongWeight,
uint64 initialShortWeight,
uint64 maintenanceLongWeight,
uint64 maintenanceShortWeight
);
event SpotRiskWeightsSet(
address indexed spotAsset,
uint64 initialLongWeight,
uint64 initialShortWeight,
uint64 maintenanceLongWeight,
uint64 maintenanceShortWeight
);
event SpreadPenaltySet(address indexed spotAsset, uint64 initial, uint64 maintenance);
event BaseAssetQuotePerpSet(address indexed spotAddress, uint32 productId);
// Liquidation Events
//////////////////////////////////////
event RequiresDispatchCallSet(bool requiresDispatchCall);
event Liquidated( // for a spread this is the perpId
address liquidator,
address liquidatee,
uint8 mode,
uint32 productId,
uint256 quantity,
uint256 liquidationPrice,
uint256 liquidationFees
);
event LiqPriceNumeratorSet(uint256 liqPriceNumerator);
event LiqPriceDenominatorSet(uint256 liqPriceDenominator);
event LiquidationFeeFractionSet(uint256 liquidationFeeFraction);
event LiquidationHealthBufferSet(uint256 liquidationHealthBuffer);
// Perp Crucible Events
//////////////////////////////////////
event PerpPositionUpdated(
address indexed subAccount,
uint32 indexed productId,
Structs.PositionState posBefore,
Structs.PositionState posAfter
);
}pragma solidity >=0.8.19;
import "../libraries/AccessControl.sol";
import "../libraries/EnumerableSet.sol";
// ______ _ __ __
// / ____/______ _______(_) /_ / /__
// / / / ___/ / / / ___/ / __ \/ / _ \
// / /___/ / / /_/ / /__/ / /_/ / / __/
// \____/_/ \__,_/\___/_/_.___/_/\___/
//
//////////////////////////////////////////
/// @notice Based contract for crucibles
/// Mk 0.0.0
abstract contract Crucible is AccessControl {
using EnumerableSet for EnumerableSet.UintSet;
// Dynamic Variables
//////////////////////////////////////
// mapping from subaccount to set of productIds for which a position is open
mapping(address => EnumerableSet.UintSet) internal openPositionIds;
// filled quantity storage
mapping(bytes32 => uint128) public filledQuantitys;
function __Crucible_init(address _addressManifest) internal {
__AccessControl_init(_addressManifest);
}
// External - Access Controlled
//////////////////////////////////////
/// @notice updates the filled quantity for a given trade, this is how much of a trade has been filled
/// for a given digest, this digest was used as the message for an EIP712 signature so is a unique
/// identifier for a given trade.
/// @dev only accessible by the order dispatch so by extension the operator
/// @param takerDigest the digest of the taker's order used in combination with their EIP712 signature
/// @param makerDigest the digest of the maker's order used in combination with their EIP712 signature
/// @param filledQuantityIncrease the quantity to increment the total filled quantity by for both users
function updateFilledQuantity(
bytes32 takerDigest,
bytes32 makerDigest,
uint128 filledQuantityIncrease
) external {
// check that the caller is the order dispatch
_isOrderDispatch();
filledQuantitys[takerDigest] += filledQuantityIncrease;
filledQuantitys[makerDigest] += filledQuantityIncrease;
}
// Basic Getters
//////////////////////////////////////
function getOpenPositionIds(address subAccount) external view returns (uint256[] memory) {
return openPositionIds[subAccount].values();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: Unlicensed
pragma solidity >=0.8.19;
import "./IPerpCrucible.sol";
library Structs {
// Ciao Structs
///////////////////////////
struct WithdrawalReceipt {
uint256 quantity; // e18
uint256 requestTimestamp;
}
// OrderDispatch Structs
///////////////////////////
struct Deposit {
address account;
uint8 subAccountId;
address asset;
uint256 quantity;
uint64 nonce;
}
struct Withdraw {
address account;
uint8 subAccountId;
address asset;
uint128 quantity;
uint64 nonce;
}
struct ApproveSigner {
address account;
uint8 subAccountId;
address approvedSigner;
bool isApproved;
uint64 nonce;
}
struct MatchedOrder {
bytes taker;
bytes[] makers;
}
struct SingleMatchedOrder {
Order taker;
bytes32 takerDigest;
Order maker;
bytes32 makerDigest;
}
// orderType:
// 0: LIMIT, 1: LIMIT_MAKER, 2: MARKET, 3: STOP_LOSS, 4: STOP_LOSS_LIMIT, 5: TAKE_PROFIT, 6: TAKE_PROFIT_LIMIT
// timeInForce:
// 0: GTC, 1: IOC, 2: FOK
struct Order {
address account;
uint8 subAccountId; // id of the sub account being used
uint32 productId;
bool isBuy; // 0 for sell, 1 for buy
uint8 orderType;
uint8 timeInForce;
uint64 expiration;
uint128 price;
uint128 quantity;
uint64 nonce;
}
struct LiquidateSubAccount {
address liquidator;
uint8 liquidatorSubAccountId;
address liquidatee;
uint8 liquidateeSubAccountId;
uint8 liquidationMode;
uint32 productId; // perp ID in case of spread
uint128 quantity;
uint64 nonce;
}
struct OrderMatchParams {
address takerSubAccount;
address makerSubAccount;
uint256 baseQuantity;
uint32 productId;
bool takerIsBuy;
uint128 executionPrice;
bool isFirstTime;
}
// Furnace Structs
///////////////////////////
/// @dev ProductRiskWeights values all denominated in e18
struct ProductRiskWeights {
uint64 initialLongWeight;
uint64 initialShortWeight;
uint64 maintenanceLongWeight;
uint64 maintenanceShortWeight;
}
struct SpreadPenalties {
uint64 initial;
uint64 maintenance;
}
struct SubAccountHealthVars {
address[] spotAssets;
uint256 assetsLen;
IPerpCrucible perpCrucible;
uint256[] perpPositionIds;
uint256 numPerpPositions;
}
// Liquidation Structs
///////////////////////////
struct LiquidationVars {
uint256 liquidationPrice;
uint256 oraclePrice;
uint256 liquidationPayment;
uint256 liquidationFees;
}
// PerpCrucible Structs
///////////////////////////
struct PositionState {
uint256 avgEntryPrice;
uint256 quantity;
bool isLong;
int256 initCumFunding;
}
struct NewPosition {
uint256 executionPrice;
uint256 quantity;
bool isLong;
}
// ProductCatalogue Structs
////////////////////////////
// each product represents an order book. for example, ETH/USDC spot market will have a different ID to ETH/BTC spot market.
struct Product {
uint8 productType; // 1 for spot, 2 for perp, 3 for move, 4 for option
address baseAsset;
address quoteAsset;
bool isProductTradeable;
uint128 takerFee;
uint128 makerFee;
bool isMakerRebate;
}
// Reader Structs
//////////////////////////
struct SpotPosition {
address spotAsset;
uint256 spotBalance;
uint256 spotPrice;
ProductRiskWeights spotRiskWeights;
}
struct PerpPosition {
uint256 perpPositionId;
PositionState perpPosition;
uint256 perpPrice;
int256 currentCumFunding;
ProductRiskWeights perpRiskWeights;
}
struct SpreadPosition {
uint256 spotPrice;
uint256 perpPrice;
int256 currentCumFunding;
uint256 spreadQuantity;
PositionState perpPos;
SpreadPenalties spreadPenalty;
}
struct UserAndSystemState {
uint256 coreCollateralDebt;
address coreCollateralAddress;
SpotPosition[] spots;
PerpPosition[] perps;
SpreadPosition[] spreads;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "../interfaces/ICiao.sol";
import "../interfaces/IFurnace.sol";
import "../interfaces/IProductCatalogue.sol";
import "../interfaces/IAddressManifest.sol";
import "../interfaces/IPerpCrucible.sol";
abstract contract AccessControl {
IAddressManifest public addressManifest;
function __AccessControl_init(address _addressManifest) internal {
addressManifest = IAddressManifest(_addressManifest);
}
function _isOwner() internal view {
require(msg.sender == addressManifest.owner(), "UNAUTHORIZED");
}
function _isAdmin() internal view {
require(msg.sender == addressManifest.admin(), "UNAUTHORIZED");
}
function _isOrderDispatch() internal view {
require(msg.sender == _orderDispatch(), "UNAUTHORIZED");
}
function _isBalanceUpdater() internal view {
require(msg.sender == _orderDispatch() || msg.sender == _liquidation(), "UNAUTHORIZED");
}
function _ciao() internal view returns (ICiao) {
return ICiao(addressManifest.manifest(1));
}
function _furnace() internal view returns (IFurnace) {
return IFurnace(addressManifest.manifest(2));
}
function _productCatalogue() internal view returns (IProductCatalogue) {
return IProductCatalogue(addressManifest.manifest(3));
}
function _orderDispatch() internal view returns (address) {
return addressManifest.manifest(4);
}
function _liquidation() internal view returns (address) {
return addressManifest.manifest(5);
}
function _perpCrucible() internal view returns (IPerpCrucible) {
return IPerpCrucible(addressManifest.manifest(7));
}
}// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.19;
import "./ICrucible.sol";
import "./Structs.sol";
/// @notice Interface for crucible
interface IPerpCrucible is ICrucible {
function subAccountPositions(uint32 productId, address subAccount)
external
view
returns (Structs.PositionState memory);
function currentCumFunding(uint32 productId) external view returns (int256);
function updatePosition(
address makerSubAccount,
address takerSubAccount,
uint32 productId,
Structs.NewPosition memory makerPosition
) external returns (int256 makerRealisedPnl, int256 takerRealisedPnl);
function updateCumulativeFundings(bytes memory fundingData) external;
}// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.19;
import "./Structs.sol";
/// @notice Interface for ciao
interface ICiao {
function deposit(address account, uint8 subAccountId, uint256 quantity, address asset)
external;
function executeWithdrawal(address account, uint8 subAccountId, uint256 quantity, address asset)
external;
function withdrawalReceipts(address subAccount, address asset)
external
view
returns (Structs.WithdrawalReceipt memory);
function updateBalance(
address takerSubAccount,
address makerSubAccount,
uint256 baseQuantity,
uint256 quoteQuantity,
uint32 productId,
bool isTakerBuy,
uint256 takerFee,
uint256 makerFee,
uint256 sequencerFee
) external;
function incrementFee(address asset, uint256 feeQuantity, address recipient) external;
function settleCoreCollateral(address subAccount, int256 quantity) external;
function getSubAccountAssets(address subAccount) external view returns (address[] memory);
function balances(address subAccount, address asset) external view returns (uint256);
function coreCollateralDebt(address subAccount) external view returns (uint256);
function depositCount(address subAccount) external view returns (uint64);
function coreCollateralAddress() external view returns (address);
function feeRecipient() external view returns (address);
function insurance() external view returns (address);
}// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.19;
import "./Structs.sol";
/// @notice Interface for the furnace
interface IFurnace {
function getSubAccountHealth(address subAccount, bool isInitial)
external
view
returns (int256);
function setPrices(bytes calldata priceData) external;
function baseAssetQuotePerpIds(address spotAddress) external view returns (uint32);
function prices(uint32 productId) external view returns (uint256);
function getSpreadPenalty(address spotAddress)
external
view
returns (Structs.SpreadPenalties memory);
function getSpotRiskWeights(address spotAddress)
external
view
returns (Structs.ProductRiskWeights memory);
function getProductRiskWeights(uint32 productId)
external
view
returns (Structs.ProductRiskWeights memory);
}// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.19;
import "./Structs.sol";
/// @notice Interface for the product catalogue
interface IProductCatalogue {
function products(uint32 productId) external view returns (Structs.Product memory);
function setProduct(uint32 productId, Structs.Product memory product) external;
function productIdToBaseAsset(uint32 productId) external view returns (address);
function baseAssetQuoteAssetSpotIds(address baseAsset, address quoteAsset)
external
view
returns (uint32);
}// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.19;
/// @notice Interface for the address manifest
interface IAddressManifest {
function manifest(uint256 index) external view returns (address);
function operator() external view returns (address);
function admin() external view returns (address);
function owner() external view returns (address);
function approveSigner(
address account,
uint8 subAccountId,
address approvedSigner,
bool isApproved
) external;
function approvedSigners(address subAccount, address approvedSigner)
external
view
returns (bool);
function checkInDigestAsUsed(bytes32 digest) external;
}// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.19;
/// @notice Interface for crucible
interface ICrucible {
function updateFilledQuantity(bytes32 takerDigest, bytes32 makerDigest, uint128 quantity)
external;
function filledQuantitys(bytes32 digest) external view returns (uint128);
function getOpenPositionIds(address subAccount) external view returns (uint256[] memory);
}{
"remappings": [
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"solmate/=lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {
"src/contracts/libraries/Commons.sol": {
"Commons": "0x0268EE65a043b90709AdD7fdB1bd40BA6Ae3c2b9"
},
"src/contracts/libraries/Parser.sol": {
"Parser": "0x93bDBA938195d4C145B2aE1aEb163ad251Ec0B60"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"OrderByteLengthInvalid","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"subAccount","type":"address"},{"indexed":true,"internalType":"uint32","name":"productId","type":"uint32"},{"components":[{"internalType":"uint256","name":"avgEntryPrice","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bool","name":"isLong","type":"bool"},{"internalType":"int256","name":"initCumFunding","type":"int256"}],"indexed":false,"internalType":"struct Structs.PositionState","name":"posBefore","type":"tuple"},{"components":[{"internalType":"uint256","name":"avgEntryPrice","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bool","name":"isLong","type":"bool"},{"internalType":"int256","name":"initCumFunding","type":"int256"}],"indexed":false,"internalType":"struct Structs.PositionState","name":"posAfter","type":"tuple"}],"name":"PerpPositionUpdated","type":"event"},{"inputs":[],"name":"addressManifest","outputs":[{"internalType":"contract IAddressManifest","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"currentCumFunding","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"filledQuantitys","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"subAccount","type":"address"}],"name":"getOpenPositionIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"address","name":"subAccount","type":"address"}],"name":"getSubAccountPosition","outputs":[{"components":[{"internalType":"uint256","name":"avgEntryPrice","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bool","name":"isLong","type":"bool"},{"internalType":"int256","name":"initCumFunding","type":"int256"}],"internalType":"struct Structs.PositionState","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addressManifest","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"subAccount","type":"address"},{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"isPositionOpenForId","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"address","name":"","type":"address"}],"name":"subAccountPositions","outputs":[{"internalType":"uint256","name":"avgEntryPrice","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bool","name":"isLong","type":"bool"},{"internalType":"int256","name":"initCumFunding","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"fundingData","type":"bytes"}],"name":"updateCumulativeFundings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"takerDigest","type":"bytes32"},{"internalType":"bytes32","name":"makerDigest","type":"bytes32"},{"internalType":"uint128","name":"filledQuantityIncrease","type":"uint128"}],"name":"updateFilledQuantity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"takerSubAccount","type":"address"},{"internalType":"address","name":"makerSubAccount","type":"address"},{"internalType":"uint32","name":"productId","type":"uint32"},{"components":[{"internalType":"uint256","name":"executionPrice","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bool","name":"isLong","type":"bool"}],"internalType":"struct Structs.NewPosition","name":"makerPosition","type":"tuple"}],"name":"updatePosition","outputs":[{"internalType":"int256","name":"takerRealisedPnl","type":"int256"},{"internalType":"int256","name":"makerRealisedPnl","type":"int256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b5061149f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063aaeb7a7511610071578063aaeb7a75146101af578063c4d66de8146101cf578063d2de1a60146101e2578063d4b8b27c14610210578063e20c4fd714610238578063fa0552361461025b57600080fd5b806312ec2eac146100ae5780635802be23146100c357806387d4b88f146101095780639c949e791461011c5780639fcd3dac14610184575b600080fd5b6100c16100bc366004610fb2565b61027b565b005b6100ec6100d1366004610ff7565b6002602052600090815260409020546001600160801b031681565b6040516001600160801b0390911681526020015b60405180910390f35b6100c1610117366004611026565b610314565b61015e61012a366004611105565b60036020818152600093845260408085209091529183529120805460018201546002830154929093015490929160ff169084565b604080519485526020850193909352901515918301919091526060820152608001610100565b600054610197906001600160a01b031681565b6040516001600160a01b039091168152602001610100565b6101c26101bd366004611105565b6103d1565b604051610100919061113c565b6100c16101dd366004611169565b610461565b6102026101f0366004611186565b60046020526000908152604090205481565b604051908152602001610100565b61022361021e3660046111a1565b61058a565b60408051928352602083019190915201610100565b61024b610246366004611250565b6105e1565b6040519015158152602001610100565b61026e610269366004611169565b610613565b6040516101009190611285565b610283610637565b600083815260026020526040812080548392906102aa9084906001600160801b03166112df565b82546101009290920a6001600160801b038181021990931691831602179091556000848152600260205260408120805485945090926102eb918591166112df565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505050565b61031c610637565b6024815161032a9190611315565b15610348576040516361b393e160e11b815260040160405180910390fd5b805160005b818110156103cc5760008080610364846004611329565b90506000610373856024611329565b905081870151935080870151925082600460008663ffffffff1663ffffffff16815260200190815260200160002060008282546103b0919061133c565b909155506103c19050602486611329565b94505050505061034d565b505050565b6103fe60405180608001604052806000815260200160008152602001600015158152602001600081525090565b5063ffffffff821660009081526003602081815260408084206001600160a01b0386168552825292839020835160808101855281548152600182015492810192909252600281015460ff1615159382019390935291015460608201525b92915050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156104a75750825b905060008267ffffffffffffffff1660011480156104c45750303b155b9050811580156104d2575080155b156104f05760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561051a57845460ff60401b1916600160401b1785555b61053c86600080546001600160a01b0319166001600160a01b03831617905550565b831561058257845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b600080610595610698565b6105c986856040518060600160405280876000015181526020018760200151815260200187604001511515158152506106fd565b91506105d68585856106fd565b905094509492505050565b6001600160a01b038216600090815260016020526040812061060c9063ffffffff80851690610cd816565b9392505050565b6001600160a01b038116600090815260016020526040902060609061045b90610cf0565b61063f610cfd565b6001600160a01b0316336001600160a01b0316146106935760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064015b60405180910390fd5b565b50565b6106a0610cfd565b6001600160a01b0316336001600160a01b031614806106c2575061063f610d70565b6106935760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015260640161068a565b63ffffffff80831660008181526003602081815260408084206001600160a01b038a1680865290835281852082516080810184528154815260018083015482870152600283015460ff161515828601529190950154606086015290855290915282209193909261076e9291610cd816565b15610b19576107d9816020015182604001516107ae57606083015163ffffffff87166000908152600460205260409020546107a99190611364565b6107d3565b63ffffffff861660009081526004602052604090205460608401516107d39190611364565b90610da2565b91508260400151151581604001511515036108db576000610837846020015183602001516108079190611329565b6020860151865161081791610dc1565b6020850151855161082791610dc1565b6108319190611329565b90610de0565b905060405180608001604052808281526020018560200151846020015161085e9190611329565b8152604086810151151560208084019190915263ffffffff89166000818152600483528381205494840194909452835260038082528284206001600160a01b038c168552825292829020845181559084015160018201559083015160028201805460ff191691151591909117905560609092015191015550610c29565b8260200151816020015110610a49576109178360200151826040015161090957845183516107a99190611364565b825185516107d39190611364565b610921908361133c565b915082602001518160200151036109a4576001600160a01b038516600090815260016020526040902061095d9063ffffffff80871690610df516565b5063ffffffff841660009081526003602081815260408084206001600160a01b038a16855290915282208281556001810183905560028101805460ff191690550155610c29565b604051806080016040528082600001518152602001846020015183602001516109cd9190611384565b8152604083810151151560208084019190915263ffffffff88166000818152600483528381205494840194909452835260038082528284206001600160a01b038b168552825292829020845181559084015160018201559083015160028201805460ff1916911515919091179055606090920151910155610c29565b610a688160200151826040015161090957845183516107a99190611364565b610a72908361133c565b915060405180608001604052808460000151815260200182602001518560200151610a9d9190611384565b8152604085810151151560208084019190915263ffffffff88166000818152600483528381205494840194909452835260038082528284206001600160a01b038b168552825292829020845181559084015160018201559083015160028201805460ff1916911515919091179055606090920151910155610c29565b60405180608001604052808460000151815260200184602001518152602001846040015115158152602001600460008763ffffffff1663ffffffff16815260200190815260200160002054815250600360008663ffffffff1663ffffffff1681526020019081526020016000206000876001600160a01b03166001600160a01b03168152602001908152602001600020600082015181600001556020820151816001015560408201518160020160006101000a81548160ff02191690831515021790555060608201518160030155905050610c278463ffffffff1660016000886001600160a01b03166001600160a01b03168152602001908152602001600020610e0190919063ffffffff16565b505b63ffffffff841660008181526003602081815260408084206001600160a01b038b16808652908352938190208151875181528784015193810193909352868201511515838301526060808801519084015280546080840152600181015460a0840152600281015460ff16151560c08401529092015460e082015290517ff8b4490b8b672adb2b556b7355855026e058630176a2b84bc12f40458577c28e918190036101000190a3509392505050565b6000818152600183016020526040812054151561060c565b6060600061060c83610e0d565b6000805460405163016ef63360e61b81526004808201526001600160a01b0390911690635bbd8cc0906024015b602060405180830381865afa158015610d47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6b9190611397565b905090565b6000805460405163016ef63360e61b8152600560048201526001600160a01b0390911690635bbd8cc090602401610d2a565b6000670de0b6b3a7640000610db783856113b4565b61060c91906113e4565b6000670de0b6b3a7640000610dd68385611412565b61060c9190611429565b600081610dd684670de0b6b3a7640000611412565b600061060c8383610e69565b600061060c8383610f63565b606081600001805480602002602001604051908101604052809291908181526020018280548015610e5d57602002820191906000526020600020905b815481526020019060010190808311610e49575b50505050509050919050565b60008181526001830160205260408120548015610f52576000610e8d600183611384565b8554909150600090610ea190600190611384565b9050808214610f06576000866000018281548110610ec157610ec161143d565b9060005260206000200154905080876000018481548110610ee457610ee461143d565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1757610f17611453565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061045b565b600091505061045b565b5092915050565b6000818152600183016020526040812054610faa5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561045b565b50600061045b565b600080600060608486031215610fc757600080fd5b833592506020840135915060408401356001600160801b0381168114610fec57600080fd5b809150509250925092565b60006020828403121561100957600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561103857600080fd5b813567ffffffffffffffff8082111561105057600080fd5b818401915084601f83011261106457600080fd5b81358181111561107657611076611010565b604051601f8201601f19908116603f0116810190838211818310171561109e5761109e611010565b816040528281528760208487010111156110b757600080fd5b826020860160208301376000928101602001929092525095945050505050565b803563ffffffff811681146110eb57600080fd5b919050565b6001600160a01b038116811461069557600080fd5b6000806040838503121561111857600080fd5b611121836110d7565b91506020830135611131816110f0565b809150509250929050565b8151815260208083015190820152604080830151151590820152606080830151908201526080810161045b565b60006020828403121561117b57600080fd5b813561060c816110f0565b60006020828403121561119857600080fd5b61060c826110d7565b60008060008084860360c08112156111b857600080fd5b85356111c3816110f0565b945060208601356111d3816110f0565b93506111e1604087016110d7565b92506060605f19820112156111f557600080fd5b506040516060810181811067ffffffffffffffff8211171561121957611219611010565b604052606086013581526080860135602082015260a0860135801515811461124057600080fd5b6040820152939692955090935050565b6000806040838503121561126357600080fd5b823561126e816110f0565b915061127c602084016110d7565b90509250929050565b6020808252825182820181905260009190848201906040850190845b818110156112bd578351835292840192918401916001016112a1565b50909695505050505050565b634e487b7160e01b600052601160045260246000fd5b6001600160801b03818116838216019080821115610f5c57610f5c6112c9565b634e487b7160e01b600052601260045260246000fd5b600082611324576113246112ff565b500690565b8082018082111561045b5761045b6112c9565b808201828112600083128015821682158216171561135c5761135c6112c9565b505092915050565b8181036000831280158383131683831282161715610f5c57610f5c6112c9565b8181038181111561045b5761045b6112c9565b6000602082840312156113a957600080fd5b815161060c816110f0565b80820260008212600160ff1b841416156113d0576113d06112c9565b818105831482151761045b5761045b6112c9565b6000826113f3576113f36112ff565b600160ff1b82146000198414161561140d5761140d6112c9565b500590565b808202811582820484141761045b5761045b6112c9565b600082611438576114386112ff565b500490565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fdfea2646970667358221220a3c5a07d3e807c50ea4bdba6572ee4f8d92dcdad948b961da2422bc69c3b8af564736f6c63430008160033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100a95760003560e01c8063aaeb7a7511610071578063aaeb7a75146101af578063c4d66de8146101cf578063d2de1a60146101e2578063d4b8b27c14610210578063e20c4fd714610238578063fa0552361461025b57600080fd5b806312ec2eac146100ae5780635802be23146100c357806387d4b88f146101095780639c949e791461011c5780639fcd3dac14610184575b600080fd5b6100c16100bc366004610fb2565b61027b565b005b6100ec6100d1366004610ff7565b6002602052600090815260409020546001600160801b031681565b6040516001600160801b0390911681526020015b60405180910390f35b6100c1610117366004611026565b610314565b61015e61012a366004611105565b60036020818152600093845260408085209091529183529120805460018201546002830154929093015490929160ff169084565b604080519485526020850193909352901515918301919091526060820152608001610100565b600054610197906001600160a01b031681565b6040516001600160a01b039091168152602001610100565b6101c26101bd366004611105565b6103d1565b604051610100919061113c565b6100c16101dd366004611169565b610461565b6102026101f0366004611186565b60046020526000908152604090205481565b604051908152602001610100565b61022361021e3660046111a1565b61058a565b60408051928352602083019190915201610100565b61024b610246366004611250565b6105e1565b6040519015158152602001610100565b61026e610269366004611169565b610613565b6040516101009190611285565b610283610637565b600083815260026020526040812080548392906102aa9084906001600160801b03166112df565b82546101009290920a6001600160801b038181021990931691831602179091556000848152600260205260408120805485945090926102eb918591166112df565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505050565b61031c610637565b6024815161032a9190611315565b15610348576040516361b393e160e11b815260040160405180910390fd5b805160005b818110156103cc5760008080610364846004611329565b90506000610373856024611329565b905081870151935080870151925082600460008663ffffffff1663ffffffff16815260200190815260200160002060008282546103b0919061133c565b909155506103c19050602486611329565b94505050505061034d565b505050565b6103fe60405180608001604052806000815260200160008152602001600015158152602001600081525090565b5063ffffffff821660009081526003602081815260408084206001600160a01b0386168552825292839020835160808101855281548152600182015492810192909252600281015460ff1615159382019390935291015460608201525b92915050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156104a75750825b905060008267ffffffffffffffff1660011480156104c45750303b155b9050811580156104d2575080155b156104f05760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561051a57845460ff60401b1916600160401b1785555b61053c86600080546001600160a01b0319166001600160a01b03831617905550565b831561058257845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b600080610595610698565b6105c986856040518060600160405280876000015181526020018760200151815260200187604001511515158152506106fd565b91506105d68585856106fd565b905094509492505050565b6001600160a01b038216600090815260016020526040812061060c9063ffffffff80851690610cd816565b9392505050565b6001600160a01b038116600090815260016020526040902060609061045b90610cf0565b61063f610cfd565b6001600160a01b0316336001600160a01b0316146106935760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064015b60405180910390fd5b565b50565b6106a0610cfd565b6001600160a01b0316336001600160a01b031614806106c2575061063f610d70565b6106935760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015260640161068a565b63ffffffff80831660008181526003602081815260408084206001600160a01b038a1680865290835281852082516080810184528154815260018083015482870152600283015460ff161515828601529190950154606086015290855290915282209193909261076e9291610cd816565b15610b19576107d9816020015182604001516107ae57606083015163ffffffff87166000908152600460205260409020546107a99190611364565b6107d3565b63ffffffff861660009081526004602052604090205460608401516107d39190611364565b90610da2565b91508260400151151581604001511515036108db576000610837846020015183602001516108079190611329565b6020860151865161081791610dc1565b6020850151855161082791610dc1565b6108319190611329565b90610de0565b905060405180608001604052808281526020018560200151846020015161085e9190611329565b8152604086810151151560208084019190915263ffffffff89166000818152600483528381205494840194909452835260038082528284206001600160a01b038c168552825292829020845181559084015160018201559083015160028201805460ff191691151591909117905560609092015191015550610c29565b8260200151816020015110610a49576109178360200151826040015161090957845183516107a99190611364565b825185516107d39190611364565b610921908361133c565b915082602001518160200151036109a4576001600160a01b038516600090815260016020526040902061095d9063ffffffff80871690610df516565b5063ffffffff841660009081526003602081815260408084206001600160a01b038a16855290915282208281556001810183905560028101805460ff191690550155610c29565b604051806080016040528082600001518152602001846020015183602001516109cd9190611384565b8152604083810151151560208084019190915263ffffffff88166000818152600483528381205494840194909452835260038082528284206001600160a01b038b168552825292829020845181559084015160018201559083015160028201805460ff1916911515919091179055606090920151910155610c29565b610a688160200151826040015161090957845183516107a99190611364565b610a72908361133c565b915060405180608001604052808460000151815260200182602001518560200151610a9d9190611384565b8152604085810151151560208084019190915263ffffffff88166000818152600483528381205494840194909452835260038082528284206001600160a01b038b168552825292829020845181559084015160018201559083015160028201805460ff1916911515919091179055606090920151910155610c29565b60405180608001604052808460000151815260200184602001518152602001846040015115158152602001600460008763ffffffff1663ffffffff16815260200190815260200160002054815250600360008663ffffffff1663ffffffff1681526020019081526020016000206000876001600160a01b03166001600160a01b03168152602001908152602001600020600082015181600001556020820151816001015560408201518160020160006101000a81548160ff02191690831515021790555060608201518160030155905050610c278463ffffffff1660016000886001600160a01b03166001600160a01b03168152602001908152602001600020610e0190919063ffffffff16565b505b63ffffffff841660008181526003602081815260408084206001600160a01b038b16808652908352938190208151875181528784015193810193909352868201511515838301526060808801519084015280546080840152600181015460a0840152600281015460ff16151560c08401529092015460e082015290517ff8b4490b8b672adb2b556b7355855026e058630176a2b84bc12f40458577c28e918190036101000190a3509392505050565b6000818152600183016020526040812054151561060c565b6060600061060c83610e0d565b6000805460405163016ef63360e61b81526004808201526001600160a01b0390911690635bbd8cc0906024015b602060405180830381865afa158015610d47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6b9190611397565b905090565b6000805460405163016ef63360e61b8152600560048201526001600160a01b0390911690635bbd8cc090602401610d2a565b6000670de0b6b3a7640000610db783856113b4565b61060c91906113e4565b6000670de0b6b3a7640000610dd68385611412565b61060c9190611429565b600081610dd684670de0b6b3a7640000611412565b600061060c8383610e69565b600061060c8383610f63565b606081600001805480602002602001604051908101604052809291908181526020018280548015610e5d57602002820191906000526020600020905b815481526020019060010190808311610e49575b50505050509050919050565b60008181526001830160205260408120548015610f52576000610e8d600183611384565b8554909150600090610ea190600190611384565b9050808214610f06576000866000018281548110610ec157610ec161143d565b9060005260206000200154905080876000018481548110610ee457610ee461143d565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1757610f17611453565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061045b565b600091505061045b565b5092915050565b6000818152600183016020526040812054610faa5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561045b565b50600061045b565b600080600060608486031215610fc757600080fd5b833592506020840135915060408401356001600160801b0381168114610fec57600080fd5b809150509250925092565b60006020828403121561100957600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561103857600080fd5b813567ffffffffffffffff8082111561105057600080fd5b818401915084601f83011261106457600080fd5b81358181111561107657611076611010565b604051601f8201601f19908116603f0116810190838211818310171561109e5761109e611010565b816040528281528760208487010111156110b757600080fd5b826020860160208301376000928101602001929092525095945050505050565b803563ffffffff811681146110eb57600080fd5b919050565b6001600160a01b038116811461069557600080fd5b6000806040838503121561111857600080fd5b611121836110d7565b91506020830135611131816110f0565b809150509250929050565b8151815260208083015190820152604080830151151590820152606080830151908201526080810161045b565b60006020828403121561117b57600080fd5b813561060c816110f0565b60006020828403121561119857600080fd5b61060c826110d7565b60008060008084860360c08112156111b857600080fd5b85356111c3816110f0565b945060208601356111d3816110f0565b93506111e1604087016110d7565b92506060605f19820112156111f557600080fd5b506040516060810181811067ffffffffffffffff8211171561121957611219611010565b604052606086013581526080860135602082015260a0860135801515811461124057600080fd5b6040820152939692955090935050565b6000806040838503121561126357600080fd5b823561126e816110f0565b915061127c602084016110d7565b90509250929050565b6020808252825182820181905260009190848201906040850190845b818110156112bd578351835292840192918401916001016112a1565b50909695505050505050565b634e487b7160e01b600052601160045260246000fd5b6001600160801b03818116838216019080821115610f5c57610f5c6112c9565b634e487b7160e01b600052601260045260246000fd5b600082611324576113246112ff565b500690565b8082018082111561045b5761045b6112c9565b808201828112600083128015821682158216171561135c5761135c6112c9565b505092915050565b8181036000831280158383131683831282161715610f5c57610f5c6112c9565b8181038181111561045b5761045b6112c9565b6000602082840312156113a957600080fd5b815161060c816110f0565b80820260008212600160ff1b841416156113d0576113d06112c9565b818105831482151761045b5761045b6112c9565b6000826113f3576113f36112ff565b600160ff1b82146000198414161561140d5761140d6112c9565b500590565b808202811582820484141761045b5761045b6112c9565b600082611438576114386112ff565b500490565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fdfea2646970667358221220a3c5a07d3e807c50ea4bdba6572ee4f8d92dcdad948b961da2422bc69c3b8af564736f6c63430008160033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.