🟢PID controller (Hard)
Available Task ✨ (3 weeks)
Last updated
Available Task ✨ (3 weeks)
Last updated
Morphine is currently using a standard two-slope interest rate model. This model is battle-tested and widely used throughout DeFi, exemple Aave, Compound and much more...
This interest rate model manages liquidity risk in the protocol through user incentives to support liquidity:
When capital is available: low interest rates to encourage borrowing.
When capital is scarce: high interest rates to encourage repayments of debt and additional supplying.
Although this model has proved useful and was a clever initial approach to the pricing problem, it has some limitations:
Model too rigid for an evolving market
Parameters adjustment too complex for on-chain calculation, too frequent for governance voting, too critical for permisionless
A yield-farming protocol might make it more interesting to borrow a stablecoin than it otherwise might have been. Instead of constantly updating the bounds of an interest rate model in response to DeFi trends, governance updates can be limited thanks to the PID controller.
A proportional–integral–derivative controller (PID) is a control loop mechanism employing feedback that is widely used in industrial control systems and a variety of other applications requiring continuously modulated control. A PID controller continuously calculates an error value e(t) as the difference between a desired setPoint (SP) and a measured process variable (PV) and applies a correction based on proportional, integral, and derivative terms (denoted P, I, and D respectively), hence the name.
The role of a PID correction algorithm is to improve 3 main characteristics of a system: speed, accuracy and stability. If you have learned engineering sciences, you probably already used it for temperature control, flow control, motor control or others... The goal is to improve the following:
a rapid rise in speed,
a real speed very close to that requested
An operation at the set speed without oscillations (accelerations, decelerations...).
P: The Proportional is calculated by multiplying the P-Gain by the error. The purpose of the proportional, is to have a large immediate reaction on the output to bring the process value close to the set point.
I : The integral will normally not have as much immediate influence on the output as the proportional, but because the integral is continuously accumulating overtime, the longer it takes for the process value to reach the set point, the more effect the integral will have on the output.
D : The purpose of the derivative is to “predict” where the process value is going, and bias the output in the opposite direction of the proportional and integral, to hopefully prevent the controller from over-shooting the set point if the ramp rate is to fast.
Borrow rate = U(t)*Scaling factor + E(t)*KP + Ki*sum(E(t)) + dE(t)/dt * Kd
U(t) : Pool Utilization
E(t) : Optimal Pool Utilization - Pool utilization
Scaling Factor, KP, Ki, Kd and Optimal Pool Utilization are model parameters
You can run this script (taken from ETH global submission) to simulate the PID.
Some traders are "intelligent" and will borrow/repay regarding the borrow rate
Some traders are "stupid" and they will borrow and repay in a random way. They represent the noise in the model.
After running simulations, we get utilization rate that are stable and high, ensuring a small gap between borrows and supplies.
Head to lib/morphine/pool/interestRateModels and create pidController.cairo
Implement the contract respecting method names as shown above
Once you are ready, setup unit test with protostar
Play with the simulation to choose good parameters and propose improvements
The Derivative Response is highly sensitive to noise in the process, you'll have to take de median of the last errors to avoid it.
Pool utilization can rapidly increase or decrease if there is a new yield farm popping, it could be interesting to have an other integral term, summing errors of the past few days to rapidly adapt borrow rates to the current situation.
All past utilizations should be stored or an accumulator is better ?