-
Notifications
You must be signed in to change notification settings - Fork 31
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
feat(vault): Lend Token collateral #447
Conversation
aebb262
to
40ec9d5
Compare
6df3a75
to
81399f5
Compare
3e4b2d3
to
bfddbfc
Compare
runtime/src/assets.rs
Outdated
@@ -83,6 +150,11 @@ impl TryFromSymbol for CurrencyId { | |||
id if id == KSM.symbol() => Ok(Token(KSM)), | |||
id if id == KBTC.symbol() => Ok(Token(KBTC)), | |||
id if id == KINT.symbol() => Ok(Token(KINT)), | |||
// Does the first character match the lend token prefix? | |||
id if id.chars().next() == Some(LEND_TOKEN_SYMBOL_PREFIX) => { |
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.
The unfortunate problem with this is that parsing would fail if we were to register any other asset which begins with Q
, we should somehow always fall-through to get_foreign_asset_by_symbol
.
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.
Found a pretty neat solution using an if-let match guard. This feature is experimental however - no bugs have been reported but it's just not well-documented enough: rust-lang/rust#51114 (the issue thread was active within the last month).
runtime/src/assets.rs
Outdated
const LEND_TOKEN_SYMBOL_PREFIX: char = 'Q'; | ||
/// The name of Lend Tokens is the name of their underlying currency, | ||
/// prefixed by `Lend`. Example: `LendPolkadot` is the `Polkadot` lend token name. | ||
const LEND_TOKEN_NAME_PREFIX: &str = "Lend"; |
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.
Is the name used anywhere? The symbol is used parsing at startup, but just wondering if we also need to add the prefix if the name()
is used.
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.
It's used to make Coingecko API calls, so not directly relevant but thought it's better to have an implementation than to panic
But we have the coingecko_id
for that..? Also, why is coingecko used at all? Or is it within the oracle?
runtime/src/rpc.rs
Outdated
/// `twox_128("PalletName") ++ twox_128("ItemName") ++ Blake2_128Concat(key) ++ key` | ||
/// So to get the actual value of the key from a raw key, we need to ignore the first | ||
/// `3 * 128 / 8` bytes, or `48` bytes. | ||
const STORAGE_KEY_HASH_PREFIX_LENGTH: usize = 48; |
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 also use this for the existing decodings?
runtime/src/rpc.rs
Outdated
/// Keys in storage maps are prefixed by two `twox_128` hashes: the pallet name and the | ||
/// storage item names. Then, assuming the map uses the `Blake2_128Concat` hasher, the layout | ||
/// looks as follows: | ||
/// `twox_128("PalletName") ++ twox_128("ItemName") ++ Blake2_128Concat(key) ++ key` |
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.
/// `twox_128("PalletName") ++ twox_128("ItemName") ++ Blake2_128Concat(key) ++ key` | |
/// `twox_128("PalletName") ++ twox_128("ItemName") ++ Blake2(key) ++ key` |
Nit: I think Blake2_128Concat
means Blake2(key) ++ key
so key
would be in there twice
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.
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.
Turns out that AssetRegistry::Metadata
is hashed with Twox64Concat
:(
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.
Added a separate decoding function for that hasher
547eda3
to
46f13d4
Compare
|
||
pub(crate) fn insert(underlying_id: CurrencyId, lend_token_id: CurrencyId) -> Result<(), Error> { | ||
log::info!( | ||
"Found loans market: {:?}, with lend token: {:?}", |
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.
FYI this prints the full struct rather than the ticker, because the concurrent listener might run before the foreign asset listener
runtime/src/rpc.rs
Outdated
@@ -663,24 +790,54 @@ impl UtilFuncs for InterBtcParachain { | |||
&vault_id.account_id == self.get_account_id() | |||
} | |||
|
|||
async fn get_foreign_assets_metadata(&self) -> Result<Vec<(u32, AssetMetadata)>, Error> { | |||
async fn get_decoded_storage_keys<T, U, F>( |
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 don't think this should be a trait function - I think this should be a private function in the impl InterBtcParachain
, just like other internal utility functions like with_unique_signer
runtime/src/rpc.rs
Outdated
))] | ||
async fn get_lend_tokens(&self) -> Result<Vec<(CurrencyId, CurrencyId)>, Error>; | ||
|
||
async fn get_decoded_storage_keys<T, U, F>( |
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'd probably not have this take a callback function, but rather an enum and have the logic inside this function. Not a huge deal if you want to keep the callback, but if so, please make it return a Result
, since &raw_key[BLAKE2_128_HASH_PREFIX_LENGTH..]
will panic if the input slice is shorter than expected
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.
You mean an enum with the hasher type of the storage key?
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
Adds the ability to run vaults with a lend token currency (e.g.
QKSM
,QUSDT
). The client reads current lending markets from storage to determine the (underlying
,lend_token
) pairs and then listens forNewMarketEvent
andUpdatedMarketEvent
to keep the pairs up-to-date.After some investigation with @sander2, it turns out that all keys from storage maps that use the
Blake2_128Concat
hasher have a 48 byte prefix than needs to be removed to decode the key. This can replace the way keys are decoded throughout the repo (for instance, inget_foreign_assets_metadata
), and doing that would also allow for reusing a single key-decoding function.This PR was tested on
wss://kintnet-api.interlay.io/parachain
withQKSM
,QUSDT
andQKBTC
to ensure the client succesfully registers the vault and generates a bitcoin wallet.Closes: #450