>> Trade Run
Hello WEB3, The project is a decentralized exchange (DEX) designed for trading futures and perpetual contracts with up to 10x leverage, offering users a seamless way to speculate on asset price movements without holding the underlying assets. Traders can access up to 10x leverage, allowing them to amplify their positions and potentially increase profits (or losses). This feature caters to more experienced traders looking to capitalize on price volatility in a highly efficient and capital-efficient way.
It is completely a Decentralized Autonomous Organization. Goverenece tokens can be get in different ways(Merkle Airdrops, Staking LP tokens, Direct buying tokens and Other DEX, CEX platforms). Tokens holders can make proposals who are having minimum proposal threashold amount to make propoasl and done voting and make updates to protocol.
Clone the repo :
>> Files Structure
- futures
- FuturesTrading.sol
- goverence
- GoverenceToken.sol
- GoverenerContract.sol
- Timelock.sol
- interface
- AggregatorV3Interface.sol
- AutomationCompatibleInterface.sol
- IHookManager
- ILPToken
- library
- PoolLibrary.sol
- perpetuals.sol
- Factory.sol
- PositionDataTypes.sol
- TradePool.sol
- TradeRunERC20.sol
- rewards
- MerkleAirdrop.sol
- Presale.sol
- StakingPool
- utils
- Multicall.sol
- MultiSigWallet.sol
- SignatureSplitter.sol
>> Goverence Tokens
>> Key Features
- Governance tokens represent ownership or voting power in this protocol.
- It is build using Openzeppelin ERC20 Votes contract.
- Holders of these tokens have the right to participate in the decision-making process, influencing the direction and future development of the project.
- Holders will make proposals and make voting to update the protocol.
- User can get the tokens in different ways
- Merkle Airdrops
- Staking Pool LP Tokens
- Presale
- DEX & CEX platforms
-
Goverence Tokens are Maximum supply of 1 Billion. Tokens are minted at initial for different
sectors.
- presale : 350 Millions Tokens(35%)
- airdrops : 60 Million Tokens(6%)
- staking pools : 200 Million Tokens(20%)
- liquidate into DEX : 130 Million Tokens(13%)
- CEX : 130 Million Tokens(13%)
- employees : 100 Million Tokens(10%)
- future uses : 30 Million Tokens(3%)
>> Key Functions
- mintTokens(): Used to mint goverence tokens for futures uses by only owner.
- delegate(): Token holder can delegate his voting power to other trusted uses to make decisions instead of him.
- delegateBySig(): Delegate voting power by signature.
- getVotes(address): Returns the current amount of votes that address has.
>> Security considirations
- Protect against "flash loan attacks", where an attacker could borrow tokens temporarily to manipulate the outcome of a vote. By implementing Num check points.
- Using secure openzeppelin smart contracts which is also gas efficient.
- Implemented a timelock for governance decisions so that any approved changes do not take effect immediately. This provides a window during which the community can review and potentially intervene if a malicious proposal is passed.
- Fixed total supply cap to 1 Billion tokens.
- Delegation is secure and resistant to bugs, one address can control through delegation
- Consider designing tokenomics or governance structures that prevent large holders ("whales") from gaining disproportionate control. Techniques like quadratic voting (which reduces the influence of large holders) can help balance power.
- Smaller token holders to participate in governance by offering rewards or making voting easier to avoid control being concentrated in a few hands.
>> Merkle Airdrops
A Merkle airdrop is a method for distributing tokens to a large number of recipients using a Merkle tree data structure. It optimizes gas costs and simplifies the airdrop process compared to traditional airdrop methods. A Merkle tree is a cryptographic structure where a root hash represents the entire set of data (recipients and amounts in this case) while reducing the need to store or verify large amounts of data on-chain.
>> Key Functions
- createRound(): Owner will create a round to claim airdrops to the users.
- updateMerkleRoot()
- updateRoundTime()
- claimAirdrop(): Claimer call this function to claim airdrop tokens for particular roundId with proofs
- removeUnclaimedTokens(): If the claim period is over and if there are any tokens remaining in that round are removed and added to ramaining tokens in the contract.
>> Security considirations
- Implemented safeguards against replay attacks where an attacker tries to reuse an already-processed Merkle proof to claim tokens multiple times.
- For any attacks, owner can pause the airdrops claiming.
>> Staking Pool
Liquidity providers get the LP tokens by investing collateral tokens in the pools. By staking that LP tokens users can get the Goverenec Tokens with 9% APY. If they stake the LP Tokens for locking fixed period they will get more APY that normal.
- 30 Days : 11% APY
- 60 Days : 12% APY
- 90 Days : 13% APY
- 120 Days : 14% APY
- More the value(price of collateral) of LP token have more the rewards were earned.
- Only certain tokens allowed to stake in the pool, which are allowed by Factoy contract.
>> Key Functions
- addStakingToken(): add the LP tokens to allow list(done by factory).
- fixedStake(): Staked for fixed period of time.
- stake(): No fixed period is locked, user can unstake his LP tokens at any time.
- unStakeFixed(): It is claimed after the staking period ended.
- unStake(): unstake at any time.
- claimRewards(): claim the goverence tokens as rewards.
>> Secuity considerations
- Users can stake the LP's by making digital signature also(using permit).
- Tokens are transfered safely using SafeERC20 library.
- Rewards are upated before the updations of state variables in the contract.
- Follows the Checks-Effects-Interactions pattern, which ensures that state changes (e.g., updating user balances) occur before external calls, mitigating reentrancy risk
- Price of the tokens is taken from Chainlink pricefeeds using AggregatorV3Interface.
- The reward distribution logic is resistant to overflow attacks
- Batch operations also done through Multicall implementations.
>> Buy Tokens
>> Key Featues
- Users can buy the goverenec tokens directly from the presale contract(marketplace).
- The price of goverenec token is changed dynamicaly from 1$ to 25$. If the tokens are solded then the price also increased based on the remaining tokens in the presale.
- The initial price of token starts from 1$.
- Only white list collateral is used to buy the tokens.
>> Key Functions
- getCurrentPrice(): get the price of goverenec token in presale.
- buyToken(): Buy the tokens using market valued collatererals.
>> Security considerations
- It implements pausable functions.
- Allow digital signatuer to approve the tokens to spend.
- Price of the collateral tokens it taken from the chainlink pricefeed securely.
>> Timelock Controller
A Timelock Controller in a Decentralized Autonomous Organization (DAO) is a crucial mechanism that introduces a delay between when a proposal is approved and when it can actually be executed. Its main purpose is to enhance security, transparency, and accountability within the DAO’s decision-making and governance processes.
>> Key Features & Security Considirations
- The timelock ensures that governance decisions, such as contract upgrades, fund transfers, or parameter changes, cannot be executed immediately after approval. This delay gives stakeholders time to review and react to potentially harmful proposals.
- If malicious actors try to push through harmful changes, the timelock delay provides an opportunity for the DAO community to respond, raise alarms, or take preventative actions (e.g., withdrawing funds, voting to cancel the proposal).
- By introducing a delay before actions can be executed, timelocks reduce the power of centralized governance entities or actors who might try to push through proposals without community input or consensus.
- The timelock adds an additional layer of security, giving multiple signers time to review and approve actions with deliberation.
- Here we allow proposal role for goverence contract address.
- If a proposal involves moving treasury funds or distributing rewards, the timelock can prevent sudden large withdrawals or malicious fund transfers, ensuring the DAO’s funds are more secure.
>> Goverence Contract
The Governance contract plays a crucial role in Decentralized Autonomous Organizations (DAOs) by providing a secure, flexible, and standardized framework for managing decentralized governance processes. It allows a DAO to operate in a decentralized manner, where decision-making power is distributed among token holders or members of the organization.
- Decentralized Decision-Making
- The OpenZeppelin Governance contract enables token holders to participate in decision-making processes by voting on proposals.
- This decentralized approach ensures that decisions are made collectively, without relying on a central authority, in line with the DAO's principles of autonomy and transparency.
- Proposals can include changes to protocol parameters, upgrades to smart contracts, or decisions on how to allocate funds.
- On-Chain Proposal Creation and Voting
- Proposal Creation: DAO members (typically token holders) can create proposals, which are specific actions or changes they want the DAO to implement.
- Proposals are usually subject to voting, and the community decides whether to approve or reject them.
- Voting Mechanism: Token holders vote on proposals using their governance tokens. The voting system is flexible, allowing for different types of voting models, such as single-choice, approval, or weighted voting (based on token holdings). OpenZeppelin Governance handles the voting process securely on-chain.
- Token-Based Voting Power
- The contract typically assigns voting power based on the number of governance tokens a participant holds. This allows stakeholders with a larger share of tokens to have more influence in the governance process, aligning voting power with economic stake in the system.
- It supports token-weighted voting, where governance tokens like ERC20 or ERC721 tokens determine the voting power of each member.
- Quorum and Threshold Management
- Quorum Requirements: The OpenZeppelin Governance contract allows for setting quorum requirements, which specify the minimum number of votes that must be cast for a proposal to be valid. This ensures that decisions are made with sufficient participation from the community.
- Voting Thresholds: DAOs can set thresholds for passing a proposal, such as requiring a simple majority, a supermajority, or other custom rules. These thresholds can vary based on the importance of the decision.
- Timelocks for Security and Transparency
- The Governance contract can be combined with a Timelock contract, which delays the execution of approved proposals.
- This delay ensures that the community has time to review the decision and act if a malicious proposal is passed.
- The timelock provides a safeguard by allowing DAO members to intervene before executing significant changes, like protocol upgrades or large fund transfers.
- Proposal Execution
- Once a proposal is approved by the majority of voters (according to predefined rules), the Governance contract can automatically execute the proposal through smart contracts. This execution is decentralized, removing the need for a trusted intermediary.
- The OpenZeppelin Governance contract integrates tightly with smart contracts to ensure that proposals can trigger actions like updating contract parameters, transferring assets, or upgrading contracts.
- Flexible Governance Models
- OpenZeppelin's contracts are modular and flexible, allowing DAOs to customize their governance system based on their specific needs.
- This includes setting different types of governance rules, such as:
- Delegated Voting: Token holders can delegate their voting power to other members, enabling those with less time or expertise to still participate indirectly in the decision-making process.
- Weighted Voting: Proposals may require different voting weights, giving more or less power to certain categories of users, such as founders, early contributors, or core developers.
>> Futures
>> Key Features
- Any user can sell their token assests for a fixed price upto some expiry date.
- Buyer can buy the contract directly or hold the contract for that price fto the given expiry date by paying some margin amount to hold the contract.
- If any seller or buyer break the contract rules seller will loss his 3% of tokens
- If buyer break the rules 3% of stike price amount is taken from the amount he paid from the margin.
- To create a contract seller have to pay some fees 0.05% of his assests based on the time difference between the creation and expiration of contract
- Owner if the Future contract id "TimeLock controller", Updation aer done through voting mechanism.
- Here we use chainlink "Automation" to close the contracts if the expiration date is met.
- Seller can update his contract before any buyer bought the contract.
- Seller can choose which tyoe of tokens(collateral) he have to accepet for payment for contract buying.
- There are 5 stages for the contract 1)Active 2) Bought 3) Settled 4) Cancelled and 5) Experied
- Users can approve the tokens by making digital signatures also.
>> Key Function
- updateSellerFee() : update the seller fees by the timelock controller.
- updateExpiry() : updating min &max expiry by timelock.
- updateMargin() : update min & max margins by timelock.
- updateVoilationFee(): Update voilation fees by timelock.
- createContract(): Any user can create contract by paying fees to open contract.
- buyContract() : Function called to buy particular contract by paying margin amount.
- settleContract(): Paying full amount to settle the contract.
- cancelContract(): This is called by the seller to cancel his contract.
- dropContract(): This is called bby the buyer afetr paying the margin amount.
- expireContract(): This is called by any one, it works only if the passed id has expired time.
- updateMarginRequirement(): updation for contract margin.
- updateCollateral(): updation for contract collaterals.
- updateExpirationDate(): updation for contract expiry times.
- withdrawTokens()
- getFee()
- getCollateralPrice()
- getCollateralAmount()
- updateContractCollateral()
- updateTimeInterval()
- addCollateral(): add collateral to while list to accepet fo payments.
- removeCollateral(): remove colllateral from whitelist.
>> Security considerations
- Used secure automation to update the contract which have expired.
- Used SafeERC20 library to transfer the ERC20 tokens.
- Price of the collateral is taken from the chainlink pricefeeds.
- Updations in the protocol is done through goverence system and owner of the FuturesTradding.sol is Timelock address.
- Updations are done before the transfering the tokens which helps from "Re-entrany attacks".
- User can interact with multiple function in a single call using multicall() function. Whichs helps to reduce his gas cost and increases users flexibility.
- To valid "rounding error" , i have used high precision in calculations.
- Complex financial operations such as opening, modifying, or closing positions should be optimized for gas efficiency.
>> Perpetuals
In decentralized finance (DeFi), perpetual contracts (or "perps") are a type of derivative instrument that allows traders to speculate on the price of an underlying asset (like cryptocurrencies) without owning the asset itself. They are similar to futures contracts but with one key difference: perpetual contracts do not have an expiry date. This means traders can hold their positions indefinitely, as long as they meet the margin requirements. The fees for the opening and closing positions are changed dynamically based on the number of open interest in that particular pool. This helps to maintain the liquidity of the pool and also helps to prevent "front running" attacks.
>> Key Features
- With any two tokens(one for Long and other for short) can create a tradepool by calling createTradePool() function by implementing HookManager contract.
- To create a pool user have to pay some fees.
- Stable coins are not alllowed as long token because long tokens should be any volatile tokens(like WBTC, WETH, LINK etc..)
- Short tokens are any types stable or non-stable tokens.
- Native Eth is not allowed to create a tradepool.
- While creating a tradepool, an ERC20 token contract also created. The owner of that ERC20 token is tradepool. Whenever liquidity providers add or remove liquidity we mint that ERC20 tokens shares using ERC-2646 vault concept to the Liquidity providers.
- If these LP ERC20 tokens are staked in staking pool, they will earn rewards goverence tokens as rewards.
- STEPS TO OPEN POSITION
- To open position select Long(if you thick the price of collateral is increased) or short(if the price of collateral will decreased)
- Long position
- Earns a profit if the token's price goes up
- Makes a loss if the token's price goes down
- Short position
- Earns a profit if the token's price goes down
- Makes a loss if the token's price goes up
- Select the type of order, there are mainly 4 types of orders 1)Market Order 2)Price Limit Order 3)Stop Loss Order 4)Time Limit Order
- Market Order: These order are created instantly at current market price
- Price Limit Order: These orders are placed when the particular given price met. Then only it will open the position automatically using chainlink. If the price was not met then it last for infinite time.
- Stop Loss Order: These orders are created at current market price, but sets a stop loss price. Where the price met then position is closed automatically. For longs the stop loss price should be less than the current price and for shorts the stop loss price should be greater than the current price.
- Time Limit Order: In this order type trade innitially gives the closing time, whatever the position is in, it is closed automatically whne the xepiry time met. It open the position at current market price.
- Selecet the collateral you want to trade and slect the collateral you have to pay.
- Enter the collateral amount you want to pay and selcet the leverage. Protocol shows the respetive size of position based on the fees, open interest, available liquidity in that pool.
- Check all the fees and margin amount and stike price.Then click place order to open the required position.
- For any order the time taken between to open and close position, protocol will take fees. If trader open the position for long time he has to pay fees more.
- If the total amount in longs is more than the shorts in the pool and new trader want to open position in long then the new trader have to pay funding fee, if he wnat to open short then no need to pay funding fee.
- NOTE : Funding fee is changed dynamically based on how much differenec between the total amouunt of longs and shorts in pool.
- Protocol is fixed to open any type of order position(0.03%)
- All the fees are send to the liquidity providers. Based on the shares the liquidity provider have we give that much of tokens.
- While closing the position protocol checks the profit/loss the trader get. If he get profit the profits are paid in terms of short collateral if he get loss the amount is subtracted from the payed amount.
- Chainlink Automation checks all the orders which are in active once in a day, if any position loss is more than they payed. Then the position is closed automatically without permission from owner.
- Using pool manager also act as bot to validating the positions every time.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
library PoolLibrary {
function getLiquidityAmount(uint256 _amount, uint256 _reserves, uint256 _totalSupply)
internal
pure
returns (uint256 liquidity)
{
uint256 minLiquidityLock = 1000;
if (_totalSupply == 0) {
require(_amount > minLiquidityLock, "Min Liquidity");
liquidity = _amount - minLiquidityLock;
// mimimum liquidity is locked perminently
} else {
liquidity = (_amount * _totalSupply) / _reserves;
}
require(liquidity > 0, "POOL : Invalid mint liquidity");
}
function getRemoveLiquidity(uint256 _liquidity, uint256 _reserves, uint256 _totalSupply)
internal
pure
returns (uint256 amount)
{
require(_totalSupply != 0, "Invalid total supply");
amount = (_liquidity * _reserves) / _totalSupply;
}
function getProtocolFee(uint256 _amountIn, uint256 _fee) internal pure returns (uint256 amountIn) {
amountIn = (_amountIn * _fee) / 10000;
}
function getFundingFee(
uint256 _collateral, // token-B
uint256 _leverage,
bool _isLong,
uint256 _longSize,
uint256 _shortSize,
uint256 _longCollateral,
uint256 _shortCollateral,
uint256 _decimals // decimals-B
) internal pure returns (uint256 fundingFee) {
fundingFee = 0;
if (_longCollateral > _shortCollateral) {
if (_isLong) {
uint256 collateralDifference = _longCollateral - _shortCollateral + _collateral;
uint256 longRatio = (_longSize * 100) / _longCollateral;
return (collateralDifference * _leverage * longRatio * _collateral) / 10 ** (_decimals + 10);
}
} else if (_longCollateral < _shortCollateral) {
if (!_isLong) {
uint256 collateralDifference = _shortCollateral - _longCollateral + _collateral;
uint256 shortRatio = (_shortSize * 100) / _shortCollateral;
return (collateralDifference * _leverage * shortRatio * _collateral) / 10 ** (_decimals + 10);
}
}
// for remaining all cases return funding fee = 0
}
function getMaintenanceMargin(
uint256 _collateral,
uint256 _leverage,
uint256 _size,
uint256 _sizeIntokens,
uint256 _minMargin
) internal pure returns (uint256 margin) {
margin = (_collateral * _minMargin) / 10000;
uint256 updatedSize = (_size + ((_collateral * _leverage) / 100));
uint256 ratio = (updatedSize * 10000) / (_sizeIntokens + _collateral);
uint256 multiplier = (_leverage * 10000) / ratio;
margin += (_collateral * multiplier) / 100000000;
}
function getSize(uint256 _collateral, uint256 _leverage, uint256 _fundingFee, uint256 _protocolFee)
internal
pure
returns (uint256)
{
// return in terms of token-B decimals
uint256 remainingCollateral = _collateral - _fundingFee - _protocolFee;
return (remainingCollateral * _leverage) / 100;
}
/**
* check leverage at 1x because at that position collateral > size
*/
function getliquidationPrice(
uint256 _collateral,
uint256 _sizeInTokenA,
uint256 _margin,
uint256 _priceA,
uint256 _priceB,
uint256 _decimalA,
uint256 _decimalB,
bool _isLong
) internal pure returns (uint256) {
// liquidation price of token-A
uint256 remainingCollateral;
if (_isLong) {
remainingCollateral = _collateral - _margin;
uint256 amount = gettokenAAmount(remainingCollateral, _priceA, _priceB, _decimalA, _decimalB);
amount = (10 ** 8 - (amount * 10 ** 8 / _sizeInTokenA));
return (_priceA * amount) / 10 ** 8;
} else {
remainingCollateral = _collateral + _margin;
uint256 amount = gettokenAAmount(remainingCollateral, _priceA, _priceB, _decimalA, _decimalB);
amount = (10 ** 8 + (amount * 10 ** 8 / _sizeInTokenA)); // by 10**8
return (_priceA * amount) / 10 ** 8; // uisng 10**8 cost more gas for every time function have to find the value of 10**8
}
}
function gettokenAAmount(uint256 _amountB, uint256 _priceA, uint256 _priceB, uint256 _decimalA, uint256 _decimalB)
internal
pure
returns (uint256 amountA)
{
amountA = (_amountB * _priceB * 10 ** 8) / _priceA;
if (_decimalA < _decimalB) {
amountA = (amountA / 10 ** (_decimalB - _decimalA + 8));
} else if (_decimalA > _decimalB) {
amountA = (amountA * 10 ** (_decimalA - _decimalB + 8));
}
}
function getTokeninUSD(uint256 _amount, uint256 _price) internal pure returns (uint256) {
return (_amount * _price) / 10 ** 8; // returns in usd amount(10**8)
}
function getPositionMaintainFee(uint256 _entryTime, uint256 _exitTime, uint256 _feePerSecond)
internal
pure
returns (uint256)
{
return (_exitTime - _entryTime) * _feePerSecond; // returns in USD(10**8)
}
function getTokenAmountFromUSD(uint256 _amountInUSD, uint256 _price, uint256 _decimals)
internal
pure
returns (uint256)
{
return (_amountInUSD * 10 ** _decimals) / _price;
}
}
>> Key Functions
Factory.sol
- createTradePool()
- getPoolData()
- computeTradePoolAddress()
TradePool.sol
- addLiquidity()
- removeLiquidity()
- _getPositionData()
- _checkLiquidityAvailable()
- openLongPosition()
- openShortPosition()
- openPriceLimitPosition()
- closePosition()
- _calculatePNL()
- changeReceiver()
- updatePriceLimitPosition()
- updateStopLossPosition()
- updateTimeLimitPosition()
- updateSize()
- _liquidatePosition()
- checkUpkeep()
- performUpkeep()
>> Security considerations
- Implement multi-signature wallets or DAO governance for contract upgrades and critical functions to avoid a single point of failure.
- Timelock controller is the owner of the any pool and the updations in the pool is done through voting mechanism.
- Carefully manage funding rates and make sure they are updated accurately to prevent gaming of the system. This can help maintain balance between long and short positions.
- Conduct thorough checks on margin requirements and collateralization to avoid under-collateralized positions. Set minimum margin thresholds and auto-liquidation processes.
- Consider gas efficiency in smart contract design to ensure that high gas costs do not create vulnerabilities, such as failed liquidations due to exceeding gas limits.
- To perform multiple actions in a single call multicall is implemented.
- Mitigate denial-of-service risks by designing contracts to avoid expensive loops or unbounded iterations that can be exploited to exhaust gas limits.
- Uses chainlink automation to liquiadate the positions to stop losses and pricefeeds to get the price of the collateral.
- Tokens are transferred only after the state variables are updated.
>> Pool Manager
Hooks are a new feature that allows developers to customize the behavior of liquidity pools by attaching smart contract logic to various stages of a trade or liquidity event. This provides unprecedented flexibility and allows for more sophisticated financial applications to be built on top of Trade-Run protocol.
These hooks can be used to modify actions like open or close positions(with different order types), liquidity additions, or removals, allowing developers to program specific rules or reactions to trades. The hooks execute custom code at various points of a pool’s lifecycle, including before or after a trade, which could be used to introduce dynamic fees, on-chain oracles, automatic liquidity management, or even complex financial logic like perpetual futures. It acts like bot to check the data and perform actions required.
List of hooks performed:
- beforeAddLiquidity()
- afterAddLiquidity()
- beforeRemoveLiquidity()
- afterRemoveLiquidity()
- beforeOpenPosition()
- afterOpenPosition()
- beforeClosePosition()
- afterClosePosition()
For a single Hook manager contract, pool creator can create multiple pools with same hook manager contract which helps to controls and maintain the pools stability and flexibilty. These hooks can make communicate with other protocols whileany hook is called. Traders can customize their positions through these hooks, which helps to increse the user experience. Liquidity Providers can add or remove there liquidity based on the open interest and avaliable liquidity in the pools.
>> Key Features to consider while creating a Hook Manager
- Checks-Effects-Interactions Pattern: Always follow the pattern where internal state changes are made before any external interaction. This prevents external contracts from manipulating state during a transaction.
- Sanitize Inputs: Thoroughly validate all input parameters (e.g., amounts, addresses, asset types) to ensure they are within expected ranges. Invalid inputs can lead to incorrect executions or even contract vulnerabilities.
- Address Validation: Ensure that only valid, whitelisted addresses can interact with specific functions within the hook manager. This prevents unauthorized contracts or users from invoking sensitive functionality.
- Access Restrictions: Implement strict access controls to ensure that only authorized entities (e.g., governance contracts or trusted addresses) can modify key parameters of the hook manager or execute sensitive hooks.
- Limit Interaction Frequency: Apply rate limiting to prevent abuse, such as users or bots repeatedly calling hooks within a short period to manipulate prices, trading volume, or pool balances.
- Fallback Mechanisms: Implement fallback mechanisms to handle oracle failures, such as switching to a backup oracle or pausing certain actions if the oracle provides invalid data.
- Avoid Overly Complex Logic: Keep the logic in hooks as simple as possible to reduce the attack surface. Complex logic introduces opportunities for unexpected interactions and edge cases that could be exploited.
- Anti-Griefing Mechanisms: Add measures that prevent malicious actors from using the liquidation mechanism to constantly liquidate users for small profits, which could harm the user experience and overall trust in the pool.
- Collateral Checks: Ensure that collateral and margin requirements are correctly enforced at every stage of the trading lifecycle. Incorrect collateral calculations can lead to insolvency risks for the pool.
- Pool Balance Security: Implement secure balance tracking to avoid cases where liquidity is improperly accounted for, leading to under-collateralized trades or withdrawals.