nolus-protocol / nolus-money-market Goto Github PK
View Code? Open in Web Editor NEWCore logic as CosmWasm contracts defining the Nolus money market
License: Apache License 2.0
Core logic as CosmWasm contracts defining the Nolus money market
License: Apache License 2.0
Price alarms are added and removed in pairs (above and below price). We need to process them independently.
Processing of fn reply()
msg is incorrect
There are a few intermediate states of a not-yet-fully opened lease. Except for RequestLoan, which is a temporary one, a lease may be in some of the rest for some time before moving forward. For that reason, we have to be able to query their state.
Create a package (in the sense of a cargo package) in the smart contracts repository that builds a binary crate that:
reads a currency specification from the standard input. An example specification is provided here.
generates the 'currency' package in the same repository. An example result is provided here. Supplementary macros-es could be created to make it easier for the tool. As guidance, a template 'currency' package should be used.
setup an instance of the Lpp contract for each currency of the "Lpns" group
setup an instance of the Oracle contract for each currency of the "Lpns" group taking into account the resolution lists
(optional) Integrate the tool as a Cargo build script
Currently, only a receive<C>()
method is available. When the currency is unknown we have to be able to get the balance in any currency. Hence we need a currency-agnostic method.
Hint: Use platform::coin_legacy::from_cosmwasm_any
An attempt to close a lease has returned the error 'Lease] The underlying loan is not fully repaid'.
A query to Lpp has revealed an existing loan for that lease. How did the lease decide that it was paid?
lease: nolus1fetyxqn4k6w5j5mkxcrxjvtaqlf8lrwre5y5z0mkm55dfnastw8ssp5nkt
chain: nolus-dev
version: v0.2.22
PriceHooks::get_affected and PriceHooks::get_hook_denoms filter out Err-s to deserialize from the storage. While that should not occur we have to trigger an error instead.
On a related note, please rename all occurrences of hook to alarm where appropriate.
Env: Dev
There are no rewards available for lenders.
Тhe Rewards_dispatcher contract is set to dispatch rewards every hour. However, rewards to the lpp are not sent automatically.
When sending rewards manually via distribute_rewards exec - rewards are delivered successfully.
Currently, the open lease form contains the target LTV of the lease. This turns out to be inconvenient to the customers. They are used to dealing with LTD, Loan-To-Downpayment.
Transform the existing field NewLeaseForm::max_ltv
into NewLeaseForm::max_ltd
and change the calculation of the borrowed amount.
Currently, we get rpc error: code = InvalidArgument desc = [Leaser] [Oracle] [Std] Generic error: Querier contract error: codespace: wasm, code: 9: query wasm contract failed: invalid request
Send to the profit
The oracle::contract::feed::get_all_prices()
should be optimized in many ways:
When a user other than the lease owner executes lease:'close' an error message should be returned.
The workflow of some of the contracts, namely oracle and time alarms, deliberately catches any error that may happen from sub-messages. The aim is for errors to not affect other alarms' delivery. That is still true, but only for application errors. System errors like ones coming from wasmd
should result in the failure of the transaction.
Realizing that the errors' design is not ideal, we shall identify wasmd
errors by checking the error string that is delivered with Reply. For example "codespace: , code: " is a good indicator of one class of such errors.
Configure swap fee permille and deduce the fee from downpayment amounts on the lease open, and from repayment amounts on the lease repay. The fee amounts should be transferred to the profit contract for later buy-back.
Although the application logic should have prevented receiving error replies at the lease contracts, for better traceability and troubleshooting we should emit events to leave some evidence.
update: decided not to swallow errors, so we return errors instead. Ultimately, that either result in a trx error, recorded and browsed later with nolusd q contractsmanager failures
, or in an error reply.
Issue Gamm Exact In transaction only for amounts != Lpn. Currently, opening a lease providing a downpayment in the same currency fails.
Currently, the process of opening a new lease borrows the maximum amount as configured with the initial liability percent. There is a requirement for providing the customer the flexibility to enter the lease with less liability than the pre-configured.
For example, if the init liability is set to 60% then for a downpayment of 100 USDC we provide a loan of 150 USDC, which is 60% of the total value of 100 + 150.
On opening a new lease, the customer should be able to provide an amount to borrow called max_loan
. It is an optional argument. When provided, the actual amount to borrow should be equal to the min of max_loan
and calculated per the initial liability configuration. If not, the existing algorithm applies.
For example, the customer may want to take only 100 USDC turning its lease into one with a 50% liability, or LTV ratio.
Currently, that is the responsibility of Lpp. The response from Lpp::loan
does contain all the data to calculate it up to the wanted point of time.
Currently, we use gov proposals directly to update contracts one by one. That labor process is error-prone and slow. In addition, it may bring services down for the time of applying all migrations.
This ticket is about migrating all new contract releases with a single proposal, i.e. atomically, as per the policy.
Assumption: The code of the new contracts is already stored on the network.
A solution based on multiple migrations is impossible since cosmwasm does not support it. The key is to create a dedicated contract Admin
that is going to orchestrate the update process. A command to the contract is executed with a gov proposal. Input parameters are the release version, and code id-s of the updated contracts with their migrate messages. Just so you know, some may not be upgraded.
First, each contract should implement a release version query. It is fed by a constant set by the cargo build.
At its core, the Admin
begins the update process by sending migration messages to the updated contracts. Note that the administrator of the contracts should be set to the Admin
address on the initial network initialization or post it with gov proposals.
Finally, the Admin
validates the migrated contracts pertaining to the release by querying their versions.
We need to get rid of singleton approach for the oracle::contract::alarms::MarketAlarms
in the oracle.
We have to use a new instance of MarketAlarms
that is tailored to the specific needs of the oracle instance, for example, the oracle base currency.
Currently, the scale passed at the dispatcher contract init is only used internally for calculations. For the sake of UI, we need it to be queried. The subtasks here are:
<500k 15%
500k - 1m 14%
1m - 2m 13%
2m - 3m 12%
3m - 4m 11%
4m - 5m 10%
5m - 7.5m 9%
7.5m - 10m 8%
10m - 15m 7%
15m - 20m 6%
20m - 25m 5%
25m - 30m 4%
30m - 40m 3%
>40m 2%
Before integrating with a DEX, any lease holds the leased asset as Lpn at its disposal on Nolus. With the DEX connectivity already set up, we should migrate the lease liquidations on_time
and on_price
workflows to use leased assets on the DEX.
The liquidation is comprised of the following steps:
Opening a lease should fail if the lease position is worth less than the min_asset
.
This issue supersedes the former one. The original description follows.
Two system parameters are defined:
- min_initial_lease_amount_lpn - the minimum amount a lease should have at the opening, for example, $100
- min_lease_amount_lpn - the minimum amount a lease should have before being liquidated fully, for example, $15. That parameter is set on opening a lease and remains intact till the lease close.
On opening a lease, that should result in an error.
On a lease liquidation, if the lease amount that remains after is less than the minimum amount then do a full liquidation. The surplus is sent to the profit.
This is not used and would simplify the code a lot.
Currently, the formula is borrow% = base% + utilization% * addon% / optimal %
where utilization% = (total_principal + total_interest) / (total_principal + total_interest + balance) * 100
.
The latter formula should become utilization% = min( (total_principal + total_interest) / balance, optimal% / (100% - optimal%)) * 100
.
For example, here below we list some particular cases:
base% = 12%, addon% = 2%, optimal% = 70%
(total_principal + total_interest) / balance | utilization% | borrow% |
---|---|---|
0 | 0 | 12 |
1 / 9 | 0.31~0.3 | 12.31~12.3 |
3 / 7 | 1.22~1.2 | 13.22~13.2 |
5 / 5 | 2.85~2.8 | 14.85~14.8 |
7 / 3 | 6.66~6.6 | 18.67~18.6 |
8 / 2 | 6.66~6.6 | 18.67~18.6 |
9 / 1 | 6.66~6.6 | 18.67~18.6 |
The elided-lifetimes-in-paths
lint is suppressed in the checks by lint.sh
.
Change the code to explicitly specify lifetimes and remove the -A
from lint.sh
.
Opening a lease should fail if:
min_sell_asset
min_sell_asset
Repaying a lease should fail if:
min_sell_asset
This issue supersedes the former one. The original description follows.
There are two system parameters:
- min_lease_repayment_lpn - the minimum amount in lpn that could be repaid, for example, $5;
- min_collectable_interest_lpn - the minimum overdue amount that could be collected by the system, for example, by partially liquidating a lease. Its initial value would be $0.01. The system would postpone collecting such amounts until they exceed the parameter. The main consequence would be enabling repayments for several older periods, not just the immediate ones.
The aim is to avoid swap errors down the open/repay flow due to zero output amount. Use a
slippage
value of 100% to guarantee an output of at least 1.
Currently, it is done for the Active state.
For supporting DEX-related operations, we have extended the Lease State Machine with operations triggered by time alarms. There we missed adding alarms' sender validation.
Currently, the calculations are done using spot prices. For improving accuracy and avoiding potential losses due to high-error calculations we have to use the same algorithm as the one at DEX.
The tests have revealed that at the sudo timeout callback, the underlying channel has not been closed. We need to implement a time-delayed start of ICA repairment, a.k.a. how we process sudo on open ICA callback - setting up a time alarm for some short period of time.
Most of the privileged actions are permitted only to the contracts admin. While there is protection from unauthorized access, moving them under sudo
operations only would bring these benefits:
wasmd
The infrastructure used, ICA, does not provide callbacks on the result of remotely started ICS20 transfers. For example, a transfer ordered via ICA on a remote chain, DEX in our case, may fail or time out. ICA does not notify the transaction origin, i.e. the Nolus contract that has initiated it.
The solution for the case of Lease transfer-in transactions is to re-init a transfer if the funds are not received past the time out of the ICS20 transaction.
Currently, the system has a bug treating alarms for prices against any currency as alarms for prices against the oracle base currency.
Unless that info is required for the web app consider removing them. That would reduce the cost of lease code migrations and the storage amount of the chain.
Potential approaches:
Neutron wasm bindings call back the contracts passing these messages. It processes any errors that they may return by recording them in the contracts manager
module. Neutron does not try to call back again.
Errors may fall into two categories, (a) system or transient, and (b) software bugs. In both cases, they should not disappear. If (a) we want to try again. If (b) it should be root caused and fixed.
Reusing the time alarms we shall implement 'retry-on-error' when processing these callbacks.
Three of the Cosmwasm messages fall into the stargate feature of the cosmwasm lib. The multi-test (MT) lib does not support them yet.
Usecase: A Nolus contract generates a stargate sub-message, for example, IbcMsg. The MT App panics when comes across such type of message.
The particular piece of code is this https://github.com/CosmWasm/cw-multi-test/blob/main/src/app.rs#L796-L805
The same approach as the one taken for custom, staking, distribution, etc should be followed. For reference, look into our custom testing::neutron::Module, and the way the AppBuilder takes it into account.
As a result, prepare a merge request at https://github.com/CosmWasm/cw-multi-test/ . Discussed that with Bart from Confio.
Re-enable the tests ignored with "No support for stargate CosmosMsg-s at cw-multi-test, "
There are CustomError variants in a few contract error types. In general, such generic errors do not convey any meaning, cause, etc, besides just a message.
We have to:
remove them
use specific errors for the cases they have been used so far. For example, both occurrences, I found, deal with some errors in handling Reply. Therefore the most reasonable would be to move that handling to platform/reply.rs and generate StdError-s instead.
In the current design, there are two borrowed and one owned Symbol types. They are not the perfect choice to represent currencies:
Suggested design:
Currency
to CurrencyType
, move it to the currency package and flip the package dependency between finance
and currency
Symbol
. Transform LeaseGroup, LpnGroup, and PaymentGroup into LeaseCurrency, LpnCurrency, and PaymentCurrency enum-s respectively. Rebrand trait Group
as trait Currency
and implement it for all of the currency enum-s.Group::maybe_visit_on_ticker(Symbol, V)
into Currency::visit(&self, V)
to allow currency type parameterized codeCurrency
as a field of CoinDTO
instead of SymbolOwned
impl From<CurrencyType-s> for <[Lease|Lpn|Payment]Group>
or use [enum_dispatch]
. Use it as a trait bound specifying membership to a groupMissing error message when a borrower tries to open a lease without having a currency price (lease/downpayment) provided by the Oracle. Currently, the result of such an attempt is: tx resolved instead of rejected which causes the lease to be blocked in the opening:buy_asset state.
Related to: #50
Now a lot of inefficiencies exist due to collecting data eagerly.
Currently, oracle::contract::feed::Feeds::calc_prices
still use the inefficient algorithm for price calculations. With the introduction of the more efficient one with oracle::contract::feed::Feeds::all_prices_iter,
we shall unify and re-use the implementation adopting it in the calculation for specific currencies. Hint: use Iterator::filter
on the currencies.
Currently, rewards cannot be dispatched because the dispatcher is not configured in the treasury. It is possible to do post genesis but would require a gov proposal.
The aim of this task is to have that configured at the genesis time. Add the dispatcher address as a parameter of the Treasury's InitMsg.
Current implementation uses submessages reply mechanism to remove successful alarms from the storage, which is not efficient.
A new algorithm should remove alarm on sending and reinsert it in case of an error.
The lease contract should re-try the same message(s)
Environment: nolus-dev
Lease addr: nolus1c32v9c0zmh2t7fe6t20zzyknnc267vxu0tlqd6py27deezt88lasfnvxsq
This lease was stuck in state "transfer_out":
. The lease had downpayment(CRO) and DAI in it's balance, I had to load it with USDC.
After that I've sent a timeout to it with sudo-contract proposal (proposal 62), and the CRO moved to the osmo account, however the USDC remained in the leaser's balance. The lease is still in the same state transfer_out
.
To see what happened with the sudo:
nolusd q txs --events "sudo._contract_address=nolus1c32v9c0zmh2t7fe6t20zzyknnc267vxu0tlqd6py27deezt88lasfnvxsq" --limit 1 --page 4
The recipient should return that info in the response in order to allow the cosmwasm reply mechanism to remove them.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.