Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added entrypoint descriptions #86

Merged
merged 5 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
217 changes: 215 additions & 2 deletions src/contracts/entrypoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,70 @@ use ink::primitives::AccountId;

#[ink::trait_definition]
pub trait Invariant {
/// Retrieves the protocol fee represented as a percentage.
#[ink(message)]
fn get_protocol_fee(&self) -> Percentage;

/// Allows an fee receiver to withdraw collected fees.
///
/// # Parameters
/// - `pool_key`: A unique key that identifies the specified pool.
///
/// # Errors
/// - Reverts the call when the caller is an unauthorized receiver.
///
/// # External contracts
/// - PSP22
#[ink(message)]
fn withdraw_protocol_fee(&mut self, pool_key: PoolKey) -> Result<(), InvariantError>;

/// Allows an admin to adjust the protocol fee.
///
/// # Parameters
/// - `protocol_fee`: The expected fee represented as a percentage.
///
/// # Errors
/// - Reverts the call when the caller is an unauthorized user.
#[ink(message)]
fn change_protocol_fee(&mut self, protocol_fee: Percentage) -> Result<(), InvariantError>;

/// Allows admin to change current fee receiver.
///
/// # Parameters
/// - `pool_key`: A unique key that identifies the specified pool.
/// - `fee_receiver`: An `AccountId` identifying the user authorized to claim fees.
///
/// # Errors
/// - Reverts the call when the caller is an unauthorized user.
#[ink(message)]
fn change_fee_receiver(
&mut self,
pool_key: PoolKey,
fee_receiver: AccountId,
) -> Result<(), InvariantError>;

/// Opens a position.
///
/// # Parameters
/// - `pool_key`: A unique key that identifies the specified pool.
/// - `lower_tick`: The index of the lower tick for opening the position.
/// - `upper_tick`: The index of the upper tick for opening the position.
/// - `liquidity_delta`: The desired liquidity provided by the user in the specified range.
/// - `slippage_limit_lower`: The price limit for downward movement to execute the position creation.
/// - `slippage_limit_upper`: The price limit for upward movement to execute the position creation.
///
/// # Events
/// - On successful transfer, emits a `Create Position` event for the newly opened position.
///
/// # Errors
/// - Fails if the user attempts to open a position with zero liquidity.
/// - Fails if the user attempts to create a position with invalid tick indexes or tick spacing.
/// - Fails if the price has reached the slippage limit.
Sniezka1927 marked this conversation as resolved.
Show resolved Hide resolved
/// - Fails if the allowance is insufficient or the user balance transfer fails.
/// - Fails if pool does not exist
///
/// # External contracts
/// - PSP22
#[ink(message)]
fn create_position(
&mut self,
Expand All @@ -39,6 +87,29 @@ pub trait Invariant {
slippage_limit_upper: SqrtPrice,
) -> Result<Position, InvariantError>;

/// Performs a single swap based on the provided parameters.
///
/// # Parameters
/// - `pool_key`: A unique key that identifies the specified pool.
/// - `x_to_y`: A boolean specifying the swap direction.
/// - `amount`: TokenAmount that the user wants to swap.
/// - `by_amount_in`: A boolean specifying whether the user provides the amount to swap or expects the amount out.
/// - `sqrt_price_limit`: A square root of price limit allowing the price to move for the swap to occur.
///
/// # Events
/// - On a successful swap, emits a `Swap` event for the freshly made swap.
/// - On a successful swap, emits a `Cross Tick` event for every single tick crossed.
///
/// # Errors
/// - Fails if the user attempts to perform a swap with zero amounts.
/// - Fails if the price has reached the specified price limit (or price associated with specified square root of price).
/// - Fails if the user would receive zero tokens.
/// - Fails if the allowance is insufficient or the user balance transfer fails.
/// - Fails if there is insufficient liquidity in pool
/// - Fails if pool does not exist
///
/// # External contracts
/// - PSP22
#[ink(message)]
fn swap(
&mut self,
Expand All @@ -49,6 +120,27 @@ pub trait Invariant {
sqrt_price_limit: SqrtPrice,
) -> Result<CalculateSwapResult, InvariantError>;

/// Performs atomic swap involving several pools based on the provided parameters.
///
/// # Parameters
/// - `amount_in`: The amount of tokens that the user wants to swap.
/// - `expected_amount_out`: The amount of tokens that the user wants to receive as a result of the swaps.
/// - `slippage`: The max acceptable percentage difference between the expected and actual amount of output tokens in a trade, not considering target price or target_sqrt_price as in the case of a swap.
/// - `swaps`: A vector containing all parameters needed to identify separate swap steps.
///
/// # Events
/// - On every successful swap, emits a `Swap` event for the freshly made swap.
/// - On every successful swap, emits a `Cross Tick` event for every single tick crossed.
///
/// # Errors
/// - Fails if the user attempts to perform a swap with zero amounts.
/// - Fails if the user would receive zero tokens.
/// - Fails if the allowance is insufficient or the user balance transfer fails.
/// - Fails if the minimum amount out after a single swap is insufficient to perform the next swap to achieve the expected amount out.
/// - Fails if pool does not exist
///
/// # External contracts
/// - PSP22
#[ink(message)]
fn swap_route(
&mut self,
Expand All @@ -58,6 +150,20 @@ pub trait Invariant {
swaps: Vec<Hop>,
) -> Result<(), InvariantError>;

/// Simulates the swap without its execution.
///
/// # Parameters
/// - `pool_key`: A unique key that identifies the specified pool.
/// - `x_to_y`: A boolean specifying the swap direction.
/// - `amount`: The amount of tokens that the user wants to swap.
/// - `by_amount_in`: A boolean specifying whether the user provides the amount to swap or expects the amount out.
/// - `sqrt_price_limit`: A square root of price limit allowing the price to move for the swap to occur.
///
/// # Errors
/// - Fails if the user attempts to perform a swap with zero amounts.
/// - Fails if the price has reached the specified limit.
Sniezka1927 marked this conversation as resolved.
Show resolved Hide resolved
/// - Fails if the user would receive zero tokens.
/// - Fails if pool does not exist
#[ink(message)]
fn quote(
&self,
Expand All @@ -68,19 +174,42 @@ pub trait Invariant {
sqrt_price_limit: SqrtPrice,
) -> Result<(TokenAmount, TokenAmount, SqrtPrice, Vec<Tick>), InvariantError>;

/// Simulates multiple swaps without its execution.
///
/// # Parameters
/// - `amount_in`: The amount of tokens that the user wants to swap.
/// - `swaps`: A vector containing all parameters needed to identify separate swap steps.
///
/// # Errors
/// - Fails if the user attempts to perform a swap with zero amounts.
/// - Fails if the user would receive zero tokens.
/// - Fails if pool does not exist
#[ink(message)]
fn quote_route(
&mut self,
amount_in: TokenAmount,
swaps: Vec<Hop>,
) -> Result<TokenAmount, InvariantError>;

/// Transfers a position between users.
///
/// # Parameters
/// - `index`: The index of the user position to transfer.
/// - `receiver`: An `AccountId` identifying the user who will own the position.
#[ink(message)]
fn transfer_position(&mut self, index: u32, receiver: AccountId) -> Result<(), InvariantError>;

/// Retrieves information about a single position.
///
/// # Parameters
/// - `index`: The index of the user position.
///
/// # Errors
/// - Fails if position cannot be found
#[ink(message)]
fn get_position(&mut self, index: u32) -> Result<Position, InvariantError>;
Sniezka1927 marked this conversation as resolved.
Show resolved Hide resolved

/// Retrieves a vector containing all positions held by the user.
#[ink(message)]
fn get_all_positions(&mut self) -> Vec<Position>;

Expand All @@ -91,22 +220,80 @@ pub trait Invariant {
pool_key: PoolKey,
) -> Result<(), InvariantError>;

/// Allows an authorized user (owner of the position) to claim collected fees.
///
/// # Parameters
/// - `index`: The index of the user position from which fees will be claimed.
///
/// # Errors
/// - Fails if the position cannot be found.
/// - Fails if the DEX has insufficient balance to perform the transfer.
///
/// # External contracts
/// - PSP22
#[ink(message)]
fn claim_fee(&mut self, index: u32) -> Result<(TokenAmount, TokenAmount), InvariantError>;

/// Removes a position. Sends tokens associated with specified position to the owner.
///
/// # Parameters
/// - `index`: The index of the user position to be removed.
///
/// # Events
/// - Emits a `Remove Position` event upon success.
///
/// # Errors
/// - Fails if Position cannot be found
///
/// # External contracts
/// - PSP22
#[ink(message)]
fn remove_position(&mut self, index: u32)
-> Result<(TokenAmount, TokenAmount), InvariantError>;

/// Allows admin to add a custom fee tier.
///
/// # Parameters
/// - `fee_tier`: A struct identifying the pool fee and tick spacing.
///
/// # Errors
/// - Fails if an unauthorized user attempts to create a fee tier.
/// - Fails if the tick spacing is invalid.
Sniezka1927 marked this conversation as resolved.
Show resolved Hide resolved
/// - Fails if the fee tier already exists.
/// - Fails if fee is invalid
#[ink(message)]
fn add_fee_tier(&mut self, fee_tier: FeeTier) -> Result<(), InvariantError>;

/// Query of whether the fee tier exists.
///
/// # Parameters
/// - `fee_tier_key`: A struct identifying the pool fee and tick spacing.
///
/// # Errors
/// - Fails if fee tier does not exist
#[ink(message)]
fn get_fee_tier(&self, key: FeeTierKey) -> Option<()>;
fn get_fee_tier(&self, key: FeeTierKey) -> Option<()>; //Result<(), InvariantError>;

/// Removes an existing fee tier.
///
/// # Parameters
/// - `fee_tier_key`: A struct identifying the pool fee and tick spacing.
#[ink(message)]
fn remove_fee_tier(&mut self, key: FeeTierKey);
Sniezka1927 marked this conversation as resolved.
Show resolved Hide resolved

/// Allows a user to create a custom pool on a specified token pair and fee tier.
Sniezka1927 marked this conversation as resolved.
Show resolved Hide resolved
/// The contract specifies the order of tokens as x and y. The choice is deterministic.
///
/// # Parameters
/// - `token_0`: The address of the first token.
/// - `token_1`: The address of the second token.
/// - `fee_tier`: A struct identifying the pool fee and tick spacing.
/// - `init_tick`: The initial tick at which the pool will be created.
///
/// # Errors
/// - Fails if the specified fee tier cannot be found.
/// - Fails if the user attempts to create a pool for the same tokens.
Sniezka1927 marked this conversation as resolved.
Show resolved Hide resolved
/// - Fails if Pool with same tokens and fee tier already exist.
#[ink(message)]
fn create_pool(
&mut self,
Expand All @@ -116,6 +303,15 @@ pub trait Invariant {
init_tick: i32,
) -> Result<(), InvariantError>;

/// Retrieves information about a pool created on a specified token pair with an associated fee tier.
///
/// # Parameters
/// - `token_0`: The address of the first token.
/// - `token_1`: The address of the second token.
/// - `fee_tier`: A struct identifying the pool fee and tick spacing.
///
/// # Errors
/// - Fails if there is no pool associated with created key
#[ink(message)]
fn get_pool(
&self,
Expand All @@ -124,9 +320,26 @@ pub trait Invariant {
fee_tier: FeeTier,
) -> Result<Pool, InvariantError>;

/// Retrieves information about a tick at a specified index.
///
/// # Parameters
Sniezka1927 marked this conversation as resolved.
Show resolved Hide resolved
/// - `key`: A unique key that identifies the specified pool.
/// - `index`: The tick index in the tickmap.
///
/// # Errors
/// - Fails if tick cannot be found
#[ink(message)]
fn get_tick(&self, key: PoolKey, index: i32) -> Result<Tick, InvariantError>;

/// Checks if the tick at a specified index is initialized.
///
/// # Parameters
/// - `key`: A unique key that identifies the specified pool.
/// - `index`: The tick index in the tickmap.
#[ink(message)]
fn get_tickmap_bit(&self, key: PoolKey, index: i32) -> bool;
fn is_tick_initialized(&self, key: PoolKey, index: i32) -> bool;

// /// Retrieves listed pools
// #[ink(message)]
// fn get_pools(&self) -> Vec<PoolKey>;
}
13 changes: 12 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@

let event_start_sqrt_price = pool.sqrt_price;
let mut event_fee_amount = TokenAmount(0);

Check warning on line 206 in src/lib.rs

View workflow job for this annotation

GitHub Actions / Run clippy and unit tests

this `else { if .. }` block can be collapsed
while !remaining_amount.is_zero() {
let (swap_limit, limiting_tick) = self.tickmap.get_closer_limit(
sqrt_price_limit,
Expand Down Expand Up @@ -908,6 +908,9 @@
.ok_or(InvariantError::FeeTierNotFound)?;

let pool_key = PoolKey::new(token_0, token_1, fee_tier)?;
if self.pools.get(pool_key).is_ok() {
return Err(InvariantError::PoolAlreadyExist);
};
let pool = Pool::create(init_tick, current_timestamp, self.state.admin);
self.pools.add(pool_key, &pool)?;

Expand Down Expand Up @@ -945,7 +948,7 @@
}

#[ink(message)]
fn get_tickmap_bit(&self, key: PoolKey, index: i32) -> bool {
fn is_tick_initialized(&self, key: PoolKey, index: i32) -> bool {
self.tickmap.get(index, key.fee_tier.tick_spacing, key)
}
fn remove_tick(&mut self, key: PoolKey, index: i32) {
Expand Down Expand Up @@ -4011,5 +4014,13 @@
alice
);
}

#[ink_e2e::test]
#[should_panic]
async fn init_exactly_same_pools(mut client: ink_e2e::Client<C, E>) -> () {
let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef);
init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y);
init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y);
}
}
}
2 changes: 1 addition & 1 deletion src/test_helpers/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use decimal::*;

Check warning on line 1 in src/test_helpers/lib.rs

View workflow job for this annotation

GitHub Actions / Run clippy and unit tests

unused import: `decimal::*`
#[macro_export]
macro_rules! address_of {
($account:ident) => {
Expand Down Expand Up @@ -632,7 +632,7 @@
// pool_key:expr => pool_key
// caller => ink_e2e account to sign call
let _msg = build_message::<$dex>($dex_address.clone())
.call(|contract| contract.get_tickmap_bit($pool_key, $index));
.call(|contract| contract.is_tick_initialized($pool_key, $index));
$client
.call(&$caller, _msg, 0, None)
.await
Expand Down
Loading