diff --git a/architecture.md b/architecture.md index bb7f916b9..a0b25c8d3 100644 --- a/architecture.md +++ b/architecture.md @@ -5,6 +5,52 @@ This section contains documentation on the architecture of the Elys chain, inclu
Click to expand/collapse +## Overview + +The diagram below illustrates the architecture of Elys Network, outlining its various modules and their interactions. The system is organized into six layers, each with specific functionalities crucial for the overall operation. + +![./modules.png](./docs/assets/modules.png) + +### Layers and Components + +1. **Core Components:** + + - **Parameters:** Configuration settings for the overall network. + - **Epochs:** Time-based intervals for system operations. + - **Clock:** Execute CosmWasm contracts sudo operations. + - **Transferhook:** Extends basic IBC transfer capabilities by integrating with the AMM module. + +2. **Data Layer:** + + - **Oracle:** Provides external data inputs, such as price feeds. + - **Asset Profile:** Maintains information about the different assets managed within the network. + +3. **Liquidity Management:** + + - **AMM (Automated Market Maker):** Facilitates decentralized trading by maintaining liquidity pools. + - **StableStake:** Manages staking of stable assets. + - **Commitment:** Handles token lockups, vesting schedules, and staking interactions. + - **Estaking:** Extends basic staking capabilities with additional functionalities. + +4. **Pool Aggregation:** + + - **Accounted Pool:** Ensures accurate accounting of assets within pools. + +5. **Trading Mechanisms:** + + - **Perpetual:** Implements perpetual trading contracts. + - **LeverageLP:** Enables leverage trading by borrowing assets from the StableStake module. + +6. **Revenue Model:** + - **Masterchef/Incentive:** Manages rewards distribution to liquidity providers. + - **Tier:** Implements membership tiers for users based on their activity. + - **Burner:** Handles token burning mechanisms to manage supply. + - **Tokenomics:** Manages the economic model and token distribution. + +### Interaction Flow + +The interaction flow between layers is depicted with arrows. Data from the Core Components feeds into the Data Layer. The Liquidity Management layer uses this data to manage liquidity, which is then aggregated in the Pool Aggregation layer. Trading mechanisms utilize the pooled liquidity for various trading activities. The Revenue Model layer ensures economic incentives and sustainability of the system. + ## Boilerplate Generation The boilerplate was generated using `ignite CLI`, which provides a convenient way to generate new chains, modules, messages, and more. The initial modules that are part of the repository include `AssetProfile` and few others, both of which were generated using the `ignite CLI`. @@ -40,11 +86,11 @@ Here are the definitions and current values of each individual parameter of the
Click to expand/collapse -## Minting +### Minting Defines the rules for automated minting of new tokens. In the current implementation, minting is entirely disabled. -## Staking +### Staking Defines the rules for staking and delegating tokens in the network. Validators and delegators must lock their tokens for a certain period to participate in consensus and receive rewards. The `unbonding_time` parameter specifies the duration for which a validator's tokens are locked after they unbond. @@ -54,7 +100,7 @@ Defines the rules for staking and delegating tokens in the network. Validators a - `Max_validators`: The maximum number of validators that can be active at once. Current value: 100. - `Bond_denom: The denomination used for staking tokens. Current value: `uelys`. -## Governance +### Governance Defines the rules for proposing and voting on changes to the network. To make a proposal, a minimum deposit of ELYS is required. The proposal must then go through a voting process where a certain percentage of bonded tokens must vote, and a certain percentage of those votes must be in favor of the proposal for it to pass. @@ -65,14 +111,14 @@ Defines the rules for proposing and voting on changes to the network. To make a - `Veto_threshold`: The percentage of no votes required to veto a proposal. Current value: 33.4%. - `Voting_period`: The period for which voting on a proposal is open. Current value: 60. -## Distribution +### Distribution Defines the distribution of rewards and fees in the network. Block proposers receive a portion of the block rewards as an incentive to maintain the network. - `Base_proposer_reward`: The base percentage of block rewards given to proposers. Current value: 1%. - `Bonus_proposer_reward`: The additional percentage of block rewards given to proposers if they include all valid transactions. Current value: 4%. -## Slashing +### Slashing Defines the penalties for validators who violate the network rules or fail to perform their duties. Validators who sign blocks incorrectly or go offline for too long will be penalized with a percentage of their bonded tokens being slashed. The `signed_blocks_window` parameter specifies the number of blocks used to determine a validator's uptime percentage, and the `min_signed_per_window` parameter specifies the minimum percentage of blocks that a validator must sign in each window to avoid being slashed. The `downtime_jail_duration` parameter specifies the duration for which a validator is jailed if they miss too many blocks. diff --git a/docs/assets/modules.png b/docs/assets/modules.png new file mode 100644 index 000000000..ce82f4b1f Binary files /dev/null and b/docs/assets/modules.png differ diff --git a/x/amm/spec/05_slippage.md b/x/amm/spec/05_slippage.md deleted file mode 100644 index cc8499d3d..000000000 --- a/x/amm/spec/05_slippage.md +++ /dev/null @@ -1,62 +0,0 @@ -# Slippage model - -On oracle pool, to prevent bots from splitting the trades into smaller pieces to reduce slippage applied on the trade, we introduce the stacked slippage model where slippage is stacked for a block. - -Oracle pool has a dynamic weight model, the weight is updated before starting the swap transactions execution and does not change until the end of the block. - -As pool weight is updated per block (not per swap tx), slippage is changed on the block based on liquidity change on the block. -Multiple trades within a single block will cumulatively increase the slippage. When same direction swaps are executed, slippage is being increased for later swaps. We call this model as `stacked slippage` model. - -## Slippage calculation - -``` -SlippageAmount = Max(0, OracleOutAmount - BalancerOutAmount) -``` - -When `BalancerOutAmount` is bigger than `OracleOutAmount`, slippage is considered as 0 not negative. - -For trades that has negative slippage tolerance for lots of opposite side trades, the value is set to 0% and it returns exactly same as oracle price. - -## How exactly is the weight updated before the swap transactions execution? What is the criteria or the algorithm behind this dynamic weight adjustment? - -Let's say pool has 1000 ATOM and 10000 USDC. And oracle has provided $11 for 1 ATOM data. -The ratio for the pool is updated to 11:10 based on USD value of each asset on the pool. - -## How exactly does the stacked slippage model prevent bots - -Since slippage is stacked, the first swap would have pretty small slippage based on oracle price. But as time goes, the slippage is increased if same direction swaps are executed. - -E.g. if a bot would like to swap 1000ATOM for USDC where slippage is 1%. -If the bot split this trade into 1000 pieces of 1 ATOM -> USDC swap, first swap slippage is 0.001%. But it's cumulatively increased as next 1 ATOM -> USDC swaps are executed. And on the block, the user can't get lower than 1% slippage for overall 1000 ATOM. - -The bot could split the swap and run on next block, but on next block, price should have been changed and therefore, bot can't estimate output amount exactly on current block. - -And therefore, we can ensure that dust amount split attack is not generating better deal than 1 time swap on the block. - -## How does the oracle play into this - -Oracle is providing price data and external liquidity data and it's not providing any other information. - -## How does the dynamic weight model relate to slippage - -Oracle based pools use balancer slippage model to prevent arbitrage opportunity on swaps with other DEXs. -It is calculating slippage from balancer model - weight and liquidity on the pool. - -When the weight is changed based on oracle price, pool weights are updated based on oracle price, and for that, price on the pool is exactly same as oracle price. - -## Are there any gas or computation considerations when updating weights or calculating slippage, especially if these operations are done frequently? - -Weight are updated when the first swap transaction is executed on the block. And all the swap transactions are executed on the endblocker. -This won't be directly affecting users' swap gas fees where transaction is only scheduled at the stage. - -The overall time complexity on the endblocker for the swap transactions take `O(n)` where `n` is the number of swaps on the block. - -## How does the model account for volatile markets or rapid price changes? - -On volatile markets, there are a lot of arbitrage opportunities between platforms for price difference. -The oracle is providing average price of those platforms, and applying slippage on top of it as well. -Therefore, this model minimize the arbitrage opportunity with other platforms on volatile markets. - -## How are users informed about the current slippage, especially if it's stacked and changing within a block? - -Slippage is based on liquidity, external liquidity and oracle price. The slippage can be calculated from balancer formula. Users set minimum out amount from slippage estimation + additional acceptable stacked slippage for the block. Uniswap is also doing same thing, you can estimate the out amount but it's not an exact amount, it can be affected by other trades. diff --git a/x/amm/spec/06_slippage.md b/x/amm/spec/06_slippage.md new file mode 100644 index 000000000..f701b6d74 --- /dev/null +++ b/x/amm/spec/06_slippage.md @@ -0,0 +1,63 @@ + + +# Slippage Model + +In the Oracle Pool, to prevent bots from exploiting slippage by splitting trades into smaller pieces, we introduce the **stacked slippage model**. This model accumulates slippage within a block, making it less advantageous for bots to break down trades. + +## Dynamic Weight Model + +The Oracle Pool employs a dynamic weight model. The weight is updated at the start of the swap transactions execution and remains constant until the end of the block. As a result, slippage is recalculated based on the liquidity changes within the block. Multiple trades within a single block will cumulatively increase slippage, particularly for swaps in the same direction, leading to the "stacked slippage" model. + +## Slippage Calculation + +The slippage amount is calculated as follows: + +$ +SlippageAmount = Max(0, OracleOutAmount - BalancerOutAmount) +$ + +When $BalancerOutAmount$ exceeds $OracleOutAmount$, slippage is considered zero, not negative. + +For trades with a negative slippage tolerance due to numerous opposite side trades, the value is set to 0%, aligning with the oracle price. + +## Dynamic Weight Adjustment Criteria + +To illustrate the dynamic weight adjustment: + +- Suppose the pool contains 1000 ATOM and 10000 USDC, with the oracle providing a price of $11 for 1 ATOM. +- The pool's ratio is updated to 11:10 based on the USD value of each asset. + +## Bot Prevention Mechanism + +The stacked slippage model discourages bots by increasing slippage with consecutive same-direction swaps within a block: + +- Initial swaps have minimal slippage based on the oracle price. +- Subsequent swaps face increased slippage, preventing lower overall slippage even if the trade is split. + +For example, a bot attempting to swap 1000 ATOM for USDC with 1% slippage: + +- Splitting the trade into 1000 swaps of 1 ATOM each would result in increasing slippage for each swap, cumulatively ensuring the overall slippage does not drop below 1%. + +This mechanism ensures that splitting trades does not offer a better deal than a single trade within the block. + +## Role of the Oracle + +The oracle provides price and external liquidity data without additional information. This ensures price accuracy and consistency across trades. + +## Dynamic Weight Model and Slippage + +Oracle-based pools use the balancer slippage model to prevent arbitrage opportunities with other DEXs. The slippage is calculated from the balancer model, considering the weight and liquidity of the pool. When the weight is updated based on the oracle price, the pool's weight aligns with the oracle price, ensuring price consistency. + +## Computational Considerations + +Weights are updated when the first swap transaction is executed within a block, with all swap transactions executed at the end of the block. This does not directly impact users' swap gas fees since the transaction is only scheduled at this stage. The time complexity for executing swap transactions at the end of the block is O(n), where n is the number of swaps within the block. + +## Handling Volatile Markets + +In volatile markets, arbitrage opportunities arise due to price differences across platforms. The oracle provides the average price from these platforms and applies slippage on top, minimizing arbitrage opportunities with other platforms during volatile conditions. + +## User Information on Slippage + +Slippage is determined by liquidity, external liquidity, and oracle price. Users can estimate slippage using the balancer formula and set a minimum acceptable out amount, accounting for stacked slippage within the block. Similar to Uniswap, users can estimate the output amount, though it may vary due to other trades. diff --git a/x/amm/spec/06_swap_txs_reordering.md b/x/amm/spec/06_swap_txs_reordering.md deleted file mode 100644 index 2ffa00651..000000000 --- a/x/amm/spec/06_swap_txs_reordering.md +++ /dev/null @@ -1,34 +0,0 @@ -# Swap transactions reordering - -To provide lowest slippage as possible on the block, module sort the swap requests into a specific order. - -This removes possibility of MEV attack on swap transactions. -MEV attacks are coming by changing transaction orders on the block. Instead of executing messages directly that is provided by validator, on the endblocker, we store the requests on transient store and execute in specific order to minimize maximum slippage. - -## To consider on algorithm - -Swap exact amount in txs -Swap exact amount out txs -Multihop txs -2+ token pools -Algorithm complexity - -## Algorithm - -- Group transactions by pool and token (In -> Out) pairs - - Mulithop txs just consider first pool and first in/out tokens to avoid complexity -- Select a random swap request - - Try execution on cache context, and check stacked slippage - - Check if opposite direction request exists (Same pool id with opposite in/out tokens) - - If opposite direction request exists, try execution on cache context, and check stacked slippage - - Apply the swap request which as lower stacked slippage - - If one of the swaps fail, not apply any changes and remove the swap request -- Repeat the process until the swap requests run-out - -### Algorithm Complexity - -`O(n)` - where `n` is number of swap requests on the block - -### Algorithm Accuracy - -This is semi-optimized solution while keeping the algorithm complexity low. diff --git a/x/amm/spec/07_swap_txs_reordering.md b/x/amm/spec/07_swap_txs_reordering.md new file mode 100644 index 000000000..59bd01c88 --- /dev/null +++ b/x/amm/spec/07_swap_txs_reordering.md @@ -0,0 +1,45 @@ + + +# Swap Transactions Reordering + +This documentation describes the mechanism used to reorder swap transactions to minimize slippage and prevent MEV (Miner Extractable Value) attacks. + +## Overview + +To achieve the lowest possible slippage within a block, this module reorders swap requests into a specific sequence. This approach mitigates the risk of MEV attacks, which exploit transaction ordering. Instead of executing transactions as they are received from the validator, the requests are stored in a transient store during the endblocker and then executed in an optimal order. + +## Key Considerations + +When designing the reordering algorithm, the following factors are taken into account: + +- Transactions that swap an exact amount in +- Transactions that swap for an exact amount out +- Multihop transactions +- Pools involving two or more tokens +- Algorithm complexity + +## Algorithm + +1. **Grouping Transactions**: Transactions are grouped by pool and token pairs (In -> Out). + - For multihop transactions, only the first pool and the first in/out tokens are considered to reduce complexity. +2. **Selection and Execution**: + + - Select a random swap request. + - Attempt to execute it in a cache context and check the resulting stacked slippage. + - Check for an existing request in the opposite direction (same pool ID with opposite in/out tokens). + - If such an opposite request exists, attempt to execute it in a cache context and check the resulting stacked slippage. + - Apply the swap request that results in lower stacked slippage. + - If either swap fails, discard the swap request without applying any changes. + +3. **Iteration**: + - Repeat the selection and execution process until all swap requests are processed. + +### Algorithm Complexity + +The complexity of the algorithm is `O(n)`, where `n` is the number of swap requests within the block. + +### Algorithm Accuracy + +This algorithm provides a semi-optimized solution, balancing accuracy and complexity. diff --git a/x/amm/spec/README.md b/x/amm/spec/README.md index 3f5819b8e..a87f517a4 100644 --- a/x/amm/spec/README.md +++ b/x/amm/spec/README.md @@ -7,20 +7,5 @@ 3. **[Keeper](03_keeper.md)** 4. **[Endpoints](04_endpoints.md)** 5. **[Risk Management](05_risk_management.md)** - -## References - -Resources: -https://www.notion.so/5-Molecule-Token-Adding-Liquidity-to-a-Multi-Asset-Pool-1fc49e859f96457a9469d9c9ed5d06cf - -Vault contract (Main logic seems to be here) -https://arbiscan.io/address/0x489ee077994B6658eAfA855C308275EAd8097C4A#code - -Reward Router - https://arbiscan.io/address/0xB95DB5B167D75e6d04227CfFFA61069348d271F5#code - -GLP manager - https://arbiscan.io/address/0x3963FfC9dff443c2A94f21b129D429891E32ec18#code - -GLP documenet - -- https://gmxio.gitbook.io/gmx/glp -- https://app.gmx.io/#/buy_glp +6. **[Slippage Model](06_slippage.md)** +7. **[Swap Transactions Reordering](07_swap_txs_reordering.md)** diff --git a/x/leveragelp/spec/06_position_workflow.md b/x/leveragelp/spec/06_position_workflow.md new file mode 100644 index 000000000..df78ad634 --- /dev/null +++ b/x/leveragelp/spec/06_position_workflow.md @@ -0,0 +1,94 @@ + + +# Position Workflow + +This document describes the workflow for opening and closing a leveraged liquidity provision (LP) position. The process involves interactions between the user, a stable stake pool, and an Automated Market Maker (AMM) pool. + +![Position Workflow](./assets/position_workflow.png) + +## 1. Opening a Leveraged LP Position + +### Step 1: Initiate Position Opening + +- **Action**: User decides to open a leveraged LP position. +- **Trigger**: User sends a request to open a position. + +### Step 2: Send Collateral Amount + +- **Action**: The user sends a collateral amount from their address to the position address. +- **Details**: + - **Source**: User's wallet (position owner) + - **Destination**: Position address + - **Amount**: Collateral specified by the user + +### Step 3: Send Borrowed Amount + +- **Action**: The system sends the borrowed amount from the stable stake pool to the position address. +- **Details**: + - **Source**: Stable stake pool + - **Destination**: Position address + - **Amount**: Borrowed funds required for leverage + +### Step 4: Join AMM Pool + +- **Action**: The system joins the AMM pool with the combined collateral and borrowed amounts. +- **Details**: + - **Source**: Position address + - **Destination**: AMM pool + - **Amount**: Collateral + Borrowed funds + +## 2. Closing a Leveraged LP Position + +### Step 1: Initiate Position Closing + +- **Action**: User decides to close the leveraged LP position. +- **Trigger**: User sends a request to close the position. + +### Step 2: Exit AMM Pool + +- **Action**: The system exits the AMM pool to retrieve both the collateral and borrowed amounts towards the position address. +- **Details**: + - **Source**: AMM pool + - **Destination**: Position address + - **Amount**: Collateral + Borrowed funds + +### Step 3: Send Borrowed and Debts Amounts + +- **Action**: The system sends both borrowed and debt amounts from the position address to the stable stake pool. +- **Details**: + - **Source**: Position address + - **Destination**: Stable stake pool + - **Amount**: Borrowed funds + Accrued interest/debts + +### Step 4: Return Remaining Amount + +- **Action**: The system sends the remaining amount back to the position owner. +- **Details**: + - **Source**: Position address + - **Destination**: User's wallet (position owner) + - **Amount**: Remaining collateral after settling the debt + +# Components Involved + +1. **User**: The entity initiating the opening and closing of leveraged LP positions. +2. **Position Address**: The smart contract or designated address handling the position-specific funds. +3. **Stable Stake Pool**: The liquidity source providing borrowed funds for leverage from StableStake module. +4. **AMM Pool**: The decentralized exchange pool where liquidity is provided from AMM module. + +# Sequence of Actions + +## Opening Position + +1. User sends a request to open a leveraged LP position. +2. Collateral is transferred from the user's wallet to the position address. +3. Borrowed funds are transferred from the stable stake pool to the position address. +4. The position address joins the AMM pool with the total funds. + +## Closing Position + +1. User sends a request to close the leveraged LP position. +2. The position address exits the AMM pool, retrieving the collateral and borrowed amounts. +3. Borrowed and debt amounts are transferred from the position address to the stable stake pool. +4. Remaining collateral is sent back to the user's wallet. diff --git a/x/leveragelp/spec/README.md b/x/leveragelp/spec/README.md index 243e9c2d6..413586f43 100644 --- a/x/leveragelp/spec/README.md +++ b/x/leveragelp/spec/README.md @@ -22,3 +22,4 @@ For more detailed information, please refer to the individual sections listed in 3. **[Keeper](03_keeper.md)** 4. **[Endpoints](04_endpoints.md)** 5. **[CLI](05_cli.md)** +6. **[Position Workflow](06_position_workflow.md)** diff --git a/x/leveragelp/spec/assets/position_workflow.png b/x/leveragelp/spec/assets/position_workflow.png new file mode 100644 index 000000000..99a6928f1 Binary files /dev/null and b/x/leveragelp/spec/assets/position_workflow.png differ