-
Notifications
You must be signed in to change notification settings - Fork 8
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
Support swaps with stablepool #114
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's start with a general comment – I'd add a new router alongside the old one, not replace its code. Call it however you want (maybe even RouterV2
) but let's not replace the current code (including traits
). The Router
(v1) is already deployed and live, we have its metadata (artifacts) committed to the repo, with deployment addresses, so let's not "erase" its existence from the main
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some small errors around caching.
let (reserve_0, reserve_1, _) = pair.get_reserves(); | ||
(vec![reserve_0, reserve_1], *fee) | ||
} | ||
Pool::StablePool(_, _) => unimplemented!(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add here a comment with the reason for which it's not implemented? Right now it looks like a temporary solution.
}; | ||
use traits::{MathError, Pair, RouterError, StablePool}; | ||
|
||
const TRADING_FEE_DENOM: u128 = 1000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const TRADING_FEE_DENOM: u128 = 1000; | |
const TRADING_FEE_DENOM_PAIR: u128 = 1000; |
(Or however you prefer) but let's make sure it's clear that this is for V2 style pools only.
} | ||
} | ||
|
||
pub fn get_reserves_with_fee(&self) -> (Vec<u128>, u8) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it have to be pub
? You're risking caller using this on a Pool::Stable
which has unimplemented!()
.
let pool_ref: contract_ref!(StablePool) = pool_id.into(); | ||
let tokens = pool_ref.tokens(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which line will fail if pool_id
turns out to not be a Stable
pool? ie pool_ref.tokens()
should then return an error, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, if pool_id
does not implement StablePool
then that line should panic
cached_pairs: Default::default(), | ||
cached_pools: Mapping::default(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: let's make it consistent.
match pool { | ||
Pool::Pair(tokens, _, _) => { | ||
self.cached_pairs.remove(tokens); | ||
self.cached_pairs.remove(tokens); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you need to destructure the tuple and remove twice – switching the order.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't read the whole thing yet, first few things that caught my eye
@@ -220,7 +220,10 @@ fn test_fees(mut session: Session) { | |||
.execute(router.swap_exact_tokens_for_tokens( | |||
swap_amount, | |||
0, | |||
vec![ice.into(), wood.into()], | |||
vec![ | |||
(ice_wood_pair.into(), ice.into()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I missed something, there are no new tests for interacting with stable pools - I think it's important to include some.
@@ -87,7 +92,7 @@ pub trait Router { | |||
deadline: u64, | |||
) -> Result<(u128, Balance), RouterError>; | |||
|
|||
/// Exchanges tokens along `path` tokens. | |||
/// Exchanges tokens along `path` pools and tokens. | |||
/// Starts with `amount_in` and pair under `(path[0], path[1])` address. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the comment is still a bit outdated
- it should be explained what are the expected values (eg. you could add a new type
Path
and explain that there), since without reading the code I wouldn't know whether its[(unused_pool, token_1), (pool_1, token_2)]
or[(pool_1, token_1), (token_2, unused_pool)]
- for me the first version seems more intuitive, but turns out it's wrong. - would be nice to have a mention about what the return value is supposed to represent
@@ -96,12 +101,12 @@ pub trait Router { | |||
&mut self, | |||
amount_in: u128, | |||
amount_out_min: u128, | |||
path: Vec<AccountId>, | |||
path: Vec<Step>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that with this type you need to pass at least one "unused" pool address, I would change it to either:
- path:
Vec<Step>
+ first_token:AccountId
, or - make
Step
field holding the poolOption<AccountId>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. Imho the path: Vec<Step>, token_in: AccountId
is cleaner and easier to understand.
@@ -185,45 +190,13 @@ pub trait Router { | |||
#[ink(message)] | |||
fn quote(&self, amount_0: u128, reserve_0: u128, reserve_1: u128) -> Result<u128, RouterError>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems weird for me to have this as a message when we have different pool types - do you know if we are currently using it somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. I'm not sure if this method is used somewhere by FE but I doubt it (it does a simple calculation which can be done off-chain).
The development continued in #117. |
The new
Router
contract will support swaps along paths that includePair
andStablePool
types of pools.Swap Path
The path is a vector of
Step
s and must consist of at least 2Step
s. Each step is a structStep(PoolId, TokenId)
. TheTokenId
describes the token in of the swap for the givenPoolId
, except for the lastStep
- the lastStep
in the path always describes the token out. ThePoolId
of the last step is ignored.E.g path
[(pool_1, token_a) , (pool_2, token_b) , (pool_x, token_c)]
can be visualized like this:Compatibility
The old Router had a "pair caching" mechanism which allowed caching custom
Pair
contracts. Also, when adding liquidity to a non-existent pair, the pair was created through theFactory
contract.To keep these features, the new Router has to cache the StablePool contracts before they can be used for swaps.
When swapping, the Router checks for the pool in the following order:
PoolId
(token_in,token_out)
(token_in,token_out)