Resistance Protocol is a inflation resistant ERC20 stablecoin called NOI, that is designed for the ethereum blockchain. The price stability comes from the floating-peg with two PID controllers that control its target price through its market price and the Consumer Price Index. Its value is backed by the locked ether collateral in CDP positions.
UML Diagram: https://app.diagrams.net/#G1ESvZRNm7P7Lv8m95BMcQB4rjX2j_kAPI
Website: https://resistanceprotocol.web.app/
For running the simulations inside a docker container, follow these steps(Ubuntu):
- Setup docker on your local machine
- In the root folder(ResistanceProtocol/) build the dockerfile: docker build -t simulation .
- Start the container: sudo docker run -it simulation /bin/bash
Before executing the simulation, external data needs to be created. External data are ETH/USD price and CPI values. NOI market does not affect these values, so they are created independently.
Folder /dataset/historical contains real world data about ether price and cpi data. To use these two files, execute the script /utils/historical_data/generate_historical_data.py. This script will make two files in /dataset/historical_processed, in the format needed in simulation, and plot 2 graphs in /images/external_data/historical/ folder. Because we have more data than we need for the simulation, a random moment in time will be picked and that data will be used in the simulation.
To create artificial data about cpi values and eth/usd market price, run script utils/artificial_data/generate_artificial_data.py. This will create 2 files in /dataset/artificial folder. Also, you will have 2 plots in images/external_data/artificial folder to view the data. You can also call the scripts generate_eth_value.py and generate_cpi_value.py independently.
Whichever option you choose, you will have the dataset/simulation_data folder with values that are going to be used in a simulation. Plots are in the images/simulation_data/ folder. Every time you run scripts for generating data for the simulation, new data will overwrite these folders, so when you execute the simulation, it will use the most recent data.
There are some quite useful parameters that the generate_eth_value.py script accepts. Run the command python utils/artificial_data/generate_eth_value.py -h to see the details. You can choose the direction where ETH price is heading, number of samples you want to create(by default, the number of samples that is going to be created is in the constants.py file), and how stable ETH price is.
-o Parameter: ETH_Trend_Growth, range(-10,10)
-n Parameter: Number of samples
-s Parameter: Stability of the eth price, 1 - low, 10 - high
ETH/USD |
---|
CPI value |
---|
There are 1000 timestamps, and the duration of one timestamp is approximately 3 hours, so that means the simulation simulates the period of around 4 months.
To run the simulation, execute the script sim1.py. To view and change quantity and parameters of different agents, see file utils/constants.py.
To execute multiple simulations with different parameters, you can modify the /parameters.py file, where you can change the number of agents in each simulation. When you execute the simulation, you will see information about each run in less detail in files /images/timestamp_graphs and /images/full_graphs, and detail information for the last executed simulation.
When the simulation is finished with executing, a few graphs will appear in the /images folder. agents.png file represents the amount of ETH and NOI each agent group has at the start of every timestamp.
full_graph.png(1) shows data after every transaction, and timestamp_graph.png(2) shows information on the start of every timestamp.
1 | 2 |
---|---|
Timestamp graph is convenient to see the market price trend, and full graph is useful to see how the market reacts to sudden changes of the market price(from malicious whales).
Controller values |
---|
More info...
Market price is mocked with ETH/NOI pool. Its size can be modified in constants file.
Some agents make decisions based on the ETH price prediction. ETH prediction is done with SVM model(see /classes/regression.py). Training and prediction is done when the eth/usd price is generated, to speed up the simulation.
There are several agents in the simulation. They are divided into 2 main groups.
Traders | Safe Holders |
---|---|
Rate traders | Regular SAFE owners |
Price traders | Leveragers |
Random traders | |
NOI trusters | |
Whale instant price setters | |
Whale instant rate setters | |
Whale longterm price setters |
Traders are agents who only make transactions to the ETH/NOI pool, and don't open positions. They buy/sell NOI at market price value, and make decisions based on the market and redemption price gap, and redemption rate.
Rate trader is an agent which swaps NOI/ETH when the redemption rate exceeds certain threshold. Each rate traders has percentage amount, a parameter that determines percent of their capital that they put for every trade. Also, it has Min/Max redemption rate, if the redemption rate is not in theese boundaries, Rate Trader is being activated.
Sell NOI | Buy NOI |
---|---|
Redemption rate < Min redemption rate and market price > redemption price | Redemption rate > Max redemption rate and market price < redemption price |
Price trader is an agent which swaps NOI/ETH when the relative difference between market and redemption price exceeds certain threshold. Each price traders has percentage amount, a parameter that determines percent of their capital that they put for every trade. Also, it has Max relative difference, if the absolute value of the gap is not in theese boundaries, Price Trader is being activated.
Sell NOI | Buy NOI |
---|---|
abs(Relative difference) < Max relative difference and market price > redemption price | abs(Relative difference) < Max relative difference and market price < redemption price |
Just random.
Noi Truster is an agent that waits for the opportunity to buy NOI when it's cheap, and then holds it forever.
Sell NOI | Buy NOI |
---|---|
- | abs(Relative difference) > Max relative difference and market price < redemption price |
Whale Instant Price Setter tries to manipulate the market price buy buying or selling all NOI at once, and pushing market price even further from the redemption price. This trader is activated when relative difference between market and redemption price exceeds certain threshold.
Sell NOI | Buy NOI |
---|---|
abs(Relative difference) > Max relative difference and market price < redemption price | abs(Relative difference) > Max relative difference and market price > redemption price |
Whale Instant Rate Setter tries to manipulate the market price buy buying or selling all NOI at once, and pushing market price even further from the redemption price. This trader is activated when redemption rate exceeds certain threshold.
Sell NOI | Buy NOI |
---|---|
Current Redemption rate < Min Redemption rate and market price > redemption price | Current Redemption rate > Max Redemption rate and market price < redemption price |
Whale Instant Rate Setter tries to manipulate the market price buy buying or selling 10% NOI at once, and pushing market price even further from the redemption price. Then, in every timestamp after that, it tries to sustain the relative difference between market and redemption price, and mess with the Integral term in the PI controller. If the current gap is further from the targetted gap, it puts more funds. It stops when it runs out of funds.
Safe holders are agents who open CDP positions, and try to maintain initial CR of their position. They try to not get liquidated, and do the boost and repay actions, which differs on the type of agent. Boost action is an action that has a goal to lower the CR, and repay action increases safe holder's CR. Same as Traders, they make decisions based on market price, redemption price, and redemption rate, but also based on the ETH prediction. If the ETH/USD price has a growing trend, they will open position, and close their positions otherwise. Each agent has its percentage of how much it is incentivised by ETH prediction. Safe holders start with only ETH capital.
Leverager is a Safe owner which leverages its ETH collateral. It opens a position when the redemption price is lower than market price more then some threshold relative difference, or when ETH has a growing trend. It can also close its position otherwise. To maintain its CR, it does boost and repay actions. In boost operation, leverager firstly takes out more loan in NOI, change that NOI to ETH on the market, and then put it in collateral. That increases its exposure to ETH. When leverager does the repay action, it takes out some amount from the collateral, change that to NOI on the market price, and use it to pay back part of the debt.
But why are there different values for the collateral and debt? That is because we take out NOI at redemption price, and sell it at market price, or buy it at market price, and then pay back the loan at redemption price. To calculate how much NOI we need to take out to boost our position to a targetted CR, we need to solve this system of equations:
When we substitute y in the first equation we get:
This is a classic quadratic equation:
Similar goes for repay action.
Safe owner is similar to a Leverager, but its boost and repay actions are different. When a safe owner boosts its position, it takes out some amout of collateral and keeps it for himself. For repay, it takes some of its internal funds, buys NOI on the market, and pays back a part of the debt.