Giter Club home page Giter Club logo

olympus-contracts's Introduction

OHM Discord Branches Coverage Badge Lines Coverage Badge Statements Coverage Badge Functions Coverage Badge

This is the front-end repo for Olympus.

🔧 Setting up Local Development

Required:

$ git clone https://github.com/OlympusDAO/olympus-frontend.git
$ cd olympus-frontend

# set up your environment variables
# read the comments in the .env files for what is required/optional
$ cp .env.example .env

# fill in your own values in .env, then =>
$ yarn
$ yarn start

# Set up Husky (for pre-commit hooks) by running:
$ yarn prepare

The site is now running at http://localhost:3000! Open the source code and start editing!

Testing

We use the Vitest test driver for unit tests, snapshot tests and e2e tests.

To run tests in interactive mode during development:

yarn test
# or
yarn test --ui

Unit Testing

Unit test files are co-located with the source code files that they test and follow the naming convention *.unit.test.ts. For example unit tests for OriginalSourceFile.ts are located in OriginalSourceFile.unit.test.ts. Valid extensions for test files are .js (JavaScript), .ts (TypeScript), .jsx (React JSX), .tsx (React TSX).

To run all unit test and see a coverage report:

yarn test:unit

Note that the focus of unit testing is to exercise all paths through the code hosted in this repo and only code hosted in this repo. To the extent possible, unit tests should abstract out dependencies such as remote API calls as well as crypto wallet APIs via mock functions.

Coverage thresholds are enforced via CI checks. If a new PR introduces regression in code coverage, the CI will fail. The goal is to keep us at a minimum level of test automation coverage as we introduce new code into the repo. To see the current coverage thresholds, see the coverageThreshold in package.json.

For integration testing automation that runs browser and remote API code as well as our own code, see the End-to-end (E2E) testing section below.

Mocking Remote API Calls

Unit tests should minimize dependency on remote API calls. Remote API calls slow down test execution and they also occasionally error, which may fail tests for reasons outside the app code being tested. Live API calls should be tested in End-to-end/Integration tests.

Here is an example unit test that conditionally mocks API calls.

Generative Testing

We use fast-check for generative testing which provides property-based coverage for ranges of input values. Here is an example of a unit test case in this repo that uses generative testing.

Snapshot Testing

We use Snapshot tests to make sure the UI does not change unexpectedly. When you make changes to the UI (intentionally), you likely will have to update the Snapshots. You can do so by running: yarn snapshot.

Here is an example snapshot test and here is the correspoding recorded snapshot. Keep in mind that for snapshot tests to be meaningful, they have to pre-populate components with variety of data sets (realistic, edge case, invalid).

Here is a good blog post about testing React components with generative data sets.

React Component Testing

We use React Testing Library to test behavior of UI components. Here is an example component test. Here is a useful cheat sheet.

Mocking React Hooks

When testing components that use React Hooks to third party libraries such as React Query or Web3Provider, it is sometimes convenient to mock these hooks in order to simulate various data inputs and edge cases.

Here is an example test case that shows how to mock React Hooks that use Web3Provider and React Query APIs.

Troubleshooting

If all tests are failing in your local environment (in particular, due to a "cannot find module" error with node_modules/babel-preset-react-app/node_modules/@babel/runtime/helpers/interopRequireDefault.js), but they should be passing (and the CI tests are passing), it's likely to be an issue with your local cache. Run the following command: yarn test --clearCache

End-to-end testing

Puppeteer (with the Dappeteer addition) is used to do browser-based end-to-end testing.

To run the tests:

  • Run the frontend, using yarn start
  • In another terminal, run the tests, using yarn test:e2e

Architecture/Layout

The files/folder structure are a WIP and may contain some unused files. The project is rapidly evolving so please update this section if you see it is inaccurate!

./src/
├── App.tsx       // Main app page
├── abi/          // Contract ABIs
├── assets/       // Static assets (SVGs)
├── components/   // Reusable individual components
├── constants/    // Addresses & common contracts
├── helpers/      // Helper methods to use in the app
├── hooks/        // Shared reactHooks
├── themes/       // Style sheets for dark vs light theme
└── views/        // Individual Views

Theme Support

Material UI components, such as Button, can use the current theme's color scheme through the color property. For example:

 <Button variant="contained" color="primary" className="cause-give-button">
  Give Yield
 </Button>

If you wish to use a theme's color scheme manually, follow these steps:

  1. Import useTheme: import { useTheme } from "@material-ui/core/styles";
  2. Instantiate the theme: const theme = useTheme();
  3. Add a style property to the component, for example:
 <Grid item className="cause-category" style={{ backgroundColor: theme.palette.background.default }}>
 {category}
 </Grid>

For the available theme properties, take a look at the themes in src/themes.

ESLint

We use ESLint to find/automatically fix problems.

  • react-app and react-hooks/recommended are important with react stuff.
  • @typescript-eslint/recommended and @typescript-eslint/eslint-recommended as recommended defaults.
  • unused-imports to automatically remove unused imports.
  • simple-import-sort to automatically sort imports alphabetically. This is opinionated, but useful because it helps avoid merge conflicts with imports (and who doesn't like neat alphabetically sorted imports anyway).
  • @typescript-eslint/explicit-function-return-type and @typescript-eslint/explicit-module-boundary-types are turned off to prioritise inferred return types over explicit return types. This is opinionated, but often times the inference Typescript makes is good enough, and sometimes help prevents type mismatches that are a pain to debug.
  • @typescript-eslint/ban-ts-comment and @typescript-eslint/ban-ts-ignore are also turned off. This could possibly be temporary, but the ability to use @ts-ignore-like directives is certainly handy as an escape hatch as we encounter errors during the migration to TS.

Reusable Components (Component Library)

Our codebase uses a custom component library extended from Material UI to make common UI patterns easy to implement on the frontend. An up-to-date list of available components, implementation examples as well as documentation is available here:

Storybook

Contributions are welcome and encouraged to our Component Library. If you see repeated UI patterns not represented in the library, or would like to enhance functionality (such as adding assets to our Icon or Token components), you're welcome to submit a PR to the component-library project. Please fully review component documentation in Storybook before submitting a PR.

Code Generation

The react-query hooks for the Cooler Loans API are automatically generated from the OpenAPI typings. If changes are made to the API, re-generate the typings using yarn codegen. This has some steps in-between, as the code generators did not correctly handle referenced files and needed to bundle them together.

🚀 Deployment

Auto deployed on Fleek.co frontend by Cloudflare. Since it is hosted via IPFS there is no running "server" component and we don't have server sided business logic. Users are served an index.html and javascript to run our applications.

Continuous deployment

Commits to the follow branches are automatically deployed to their respective URLs.

Branch URL
master https://app.olympusdao.finance
develop https://staging.olympusdao.finance

Pull Requests: Each PR into master will get its own custom URL that is visible on the PR page. QA & validate changes on that URL before merging into the develop branch.

Cooler Loans Dashboard

The data in the Cooler Loans Dashboard is served by an API that generates time-series data not possible in a subgraph. See the cooler-loans-api repository for details.

Different endpoints are used in different circumstances:

  • Build (deployed by Fleek): production
  • Local development: dev
  • If VITE_COOLER_LOANS_API_ENDPOINT is specified in an environment variable, it will be used regardless

Treasury Dashboard

The data in the Treasury Dashboard is powered by subgraphs hosted by the Graph Protocol and served using GraphQL. There are a few limitations, however:

  • Each subgraph can index only one blockchain, so there are subgraphs deployed for each blockchain.
  • The implementation of pagination in the Graph Protocol's GraphQL server is very basic, and requires running through successive date ranges in order to piece together results.

Using infinite queries (generated by graphql-codegen), a custom paginator and custom code to combine results from different blockchains, this was previously implemented client-side. However, the code was very brittle, and sometimes suffered from stale queries.

This has since been improved by adding Wundergraph middleware (hosted on Wundergraph Cloud) that handles combining results and pagination server-side. The complete data set is then retrieved using react-query and a generated client, @olympusdao/treasury-subgraph-client.

Wundergraph Node URL

The Wundergraph client is pre-configured with the production endpoint (referred to as a public node URL).

A developer may wish to use a different endpoint during development (e.g. to test changes that are not live in production). To achieve this, prefix the yarn start command with the VITE_WG_PUBLIC_NODE_URL variable, e.g. VITE_WG_PUBLIC_NODE_URL=http://localhost:9991 yarn start. It is recommended to define the variable this way, rather than in .env, as it makes the variable override explicit.

Known Issues

The Treasury Dashboard has a notification banner to proactively communicate any known issues to users. Content is sourced from a Markdown file, and can be edited within the GitHub interface here.

If editing the production content, opt to create a new branch and pull request, so that it can be merged into production.

How to commit changes to the Known Issues Markdown file

🗣 Community and Contributions

Deploy Your Own Frontend

Deploy with Vercel Deploy to Netlify

olympus-contracts's People

Contributors

0xjem avatar 0xlienid avatar 0xocnus avatar c-n-o-t-e avatar finaglelord avatar ind-igo avatar jextor avatar kushal256 avatar mirru2532 avatar olyzeus avatar paul4912 avatar tonypiano avatar zayen-x avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

olympus-contracts's Issues

[Non-Core - Tyche] Yield Streamer for Olympus Give

Motivation:
It's been requested in the discord for a contract to allow users to deposit their ohm and allow the yield to be converted to DAI in whatever time interval they want. The goal of the contract is to automate that and socialise the gas costs.

User Flow:
Users deposit their gOHM into the contract. They set parameters like userMinimumDaiThreshold(Lowest amount of dai they willing to accumulate before its send to them) and paymentInterval(minimum time elapse before their ohm yields are swapped into dai).

The DAO runs a gelato job so every once in a while(week maybe) it upkeeps the contract. During an upkeep users whos payment Interval has passed will have their yield in OHM swapped to DAI. If the amount of DAI they have to claim passes a user set threshold they will have it sent to their address they put. The DAO will get a fee in gOHM every time the swap to DAI happens. This will essentially pay for the gas costs of up-keeping the contract.

Users also have the option to withdraw at any time or claim their yield at any time in gOhm or DAI.

Guide to Writing Allocator Contracts

The following is a guide for interacting with the treasury as a reserve allocator.

A reserve allocator is a contract that deploys funds into external strategies, such as Aave, Curve, etc.

Treasury Address: 0x31F8Cc382c9898b273eff4e0b7626a6987C846E8

Managing:
The first step is withdraw funds from the treasury via the "manage" function.
"Manage" allows an approved address to withdraw excess reserves from the treasury.
Note that this contract must have the "reserve manager" permission, and that withdrawn reserves decrease the treasury's ability to mint new OHM (since backing has been removed).

function manage( address _token, uint _amount ) external;
Pass in the token address and the amount to manage. The token will be sent to the contract calling the function.

Managing treasury assets should look something like this:
treasury.manage( DAI, amountToManage );

Returning:
The second step is to return funds after the strategy has been closed.
We utilize the "deposit" function to do this. Deposit allows an approved contract to deposit reserve assets into the treasury, and mint OHM against them. In this case however, we will NOT mint any OHM. This will be explained shortly.
Note that the contract must have the "reserve depositor" permission, and that deposited reserves increase the treasury's ability to mint new OHM (since backing has been added).

function deposit( address _from, uint _amount, address _token, uint _profit ) external returns ( uint send_ );
Pass in the address sending the funds (most likely the allocator contract), the amount to deposit, and the address of the token. The final parameter, profit, dictates how much OHM needs to be minted. send_, the amount of OHM to send, equals the value of amount minus profit.
To ensure no OHM is minted, we first get the value of the asset, and pass that in as profit.

function valueOf( address _token, uint _amount ) public view returns ( uint value_ );
Pass in the token address and amount to get the treasury value.

All together, returning funds should look something like this:
treasury.deposit( address(this), amountToReturn, DAI, treasury.valueOf( DAI, amountToReturn ) );

Old Token in Lists

Hi, I believe your token is not updated in Kleros List: https://t2cr-docs.readthedocs.io/en/latest/

See https://tokenlists.org/token-list?url=t2crtokens.eth

There you will see the V1 token only.

This is an issue because if people want to buy it they will be buying the wrong token at the wrong price: https://tokenlists.org/token-list?url=t2crtokens.eth

Just to do a quick test and see the issue, try buying the token in Uniswap or CowSwap https://cowswap.exchange

image

image

You are offered the wrong token, and the USD estimation is misleading, because of the big price difference between v1 and v2

BondDepository.sol for v1.1 does not accept Deposits as per script

Screenshot - 11_24_2021 , 8_19_11 AM

I get a reversion -32015 - which is apparently an "Address not payable" error when i try to deploy and then do the final test of the deposits into the Bonds.

I have tried numerous times now and keep getting the same end result for a week now on 2 different chains.

Any idea what the issue may be?

Thanks!

Treasury: Removing liquidity tokens and reserve tokens right after adding it to the registry

I was taking a look at the Treasury contract and I notice that the function enable has a weird behavior when it comes to LIQUIDITYTOKEN and RESERVETOKEN.

Around the line 318 we have the following steps inside the enable function:

(bool registered, ) = indexInRegistry(_address, _status);
if (!registered) {
    registry[_status].push(_address);

    if (_status == STATUS.LIQUIDITYTOKEN || _status == STATUS.RESERVETOKEN) {
        (bool reg, uint256 index) = indexInRegistry(_address, _status);
        if (reg) {
            delete registry[_status][index];
        }
    }
}

The function checks if the checks if the address that we're trying to add to the registry is already registered, if it isn't it puts the address in the array of that particular STATUS.

The problem begins when the we're trying to enable a LIQUIDITYTOKEN or a RESERVETOKEN. Right after pushing the address to the registry, if it's any of the two STATUS mentioned above it removes soon after. So the first question here: why not simply checking if it's a LIQUIDITYTOKEN or a RESERVETOKEN before pushing the addresses to the registry?

The problem continues when we check other functions in the body of the Treasury contract.
For example, the function auditReserves uses both liquidity tokens and reserve tokens registered to update the totalReserves, but as both gets delete on the time of creation we end up with an array filled with zero addresses, therefore when we check the balances of each token, we'll always get zero which results in the totalReserves never being updated, since it uses those values to add to that variable.

With that in mind, the next question would be how the totalReserves is being updated after we call the deposit function on the BondDepository contract? Since the function mentioned doesn't call the deposit function on the Treasury contract, it simply uses a regular transfer from an ERC-20 token

`yarn run start` fails with "Error: ENOENT: no such file or directory"

Hi,

When trying the commands shown in the README, I got the following error:

➜  olympus-contracts git:(deployment) ✗ yarn run start         
yarn run v1.22.15
$ yarn run typechain
$ TS_NODE_TRANSPILE_ONLY=true hardhat typechain
Generating typings for: 0 artifacts in dir: types for target: ethers-v5
Successfully generated 242 typings!
$ hardhat node --network hardhat
Nothing to compile
No need to generate any newer typings.
deploying "OlympusAuthority" (tx: 0xa202cf1880954a127e917909d8d7fb860ad5e70c95b00ff9c3c00df0c51e17fe)...Error HH604: Error running JSON-RPC server: ERROR processing /olympus-contracts/scripts/deploy/000_deploy_authority.ts:
Error: ENOENT: no such file or directory, open '/olympus-contracts/artifacts/build-info/957f20a5ad9a91e108198aa294b9cab6.json'

For more info go to https://hardhat.org/HH604 or run Hardhat with --show-stack-traces
error Command failed with exit code 1.

Effectively, as specified by the error message, 957f20a5ad9a91e108198aa294b9cab6.json doesn't exists, a weird detail if that deployments/localhost directory gets deleted by the script.

Any insights?

Thanks.

About how contracts automatically deal with buy back and burn.

GM, I have some questions with 👇:

When OHM trades below 1 DAI, 
how the contract buy back and burn OHM? 
And could I know the exact code lines that written in the contract. 
Could I know exactly how this mechanism works(how to buy back, how to know when should buy back, etc.)?

Because I don't see how the contract handles this automatically.
Looking forward to your reply. :)
Thank you. Have a good coding day.

npx hardhat test

Hi, just trying to run your test suite to see how your contract works. I usually start with trying to run npx hardhat test Some mocks appear missing that are easy to get, like the TestTokens 1&2 and the uniswap v2-core stuff, but I'm not sure where to find this one. I see a StandardBondingCalculator but no DebtCalculator in the repo.

MockDebtCalculatorContract = await ethers.getContractFactory('MockDebtCalculator');

Am I missing some docs around local deployments? I'm seeing some people ask around for it, and even a dockerized e-2-e in the PRs, but other than that I'm not sure. I've also hopped around the Development Discord Server, but I'm not looking to commit time to the project, just to do a technical due dilligence

Thanks!

What does 'gon' stand for?

Currently read through the contracts, but get stuck at sOlympusERC20.sol.
What does 'gon' stand for? Is it an abbreviation of something?

Changing The Blockchain Type.

Hello there!
I would like to ask how to change the blockchain type on the contract from Ethereum to Binance.
Thanks in advance.

How to distribute in rebase mechanism

Hello, everyone.
I have researched OHM contract and have learnt much more.
But I have some questions about rebase mechanism.
I have understood like this.
When user stake and/or unstake, rebase is performed.
And then function distributor in Distributor.sol is called.
But in that function, I have noticed there is an array variable called "info".
I understood this variable stores stakers' addresses. But I can't find when the user's address is added to this variable.
I have tried to find functions "addRecipient", "removeRecipient" and "setAdjustment" in contract and frontend, but have nothing.
Is there any other platform to call policy functions?
When is the user added to the info array variable?
Looking forward to your kind answers.
Thanks.

V2 Treasury: `enable` method never allows for adding `LIQUIDITY_TOKEN` and `RESERVE_TOKEN` to the registry

@olyzeus The following lines effectively prohibit the permissioned Governor from adding any liquidity or reserve assets to the treasury whitelist:

(bool registered, ) = indexInRegistry(_address, _status);
if (!registered) {
registry[_status].push(_address);
if (_status == STATUS.LIQUIDITYTOKEN || _status == STATUS.RESERVETOKEN) {
(bool reg, uint256 index) = indexInRegistry(_address, _status);
if (reg) {
delete registry[_status][index];
}
}
}

(bool registered, ) = indexInRegistry(info.toPermit, info.managing);
if (!registered) {
registry[info.managing].push(info.toPermit);
if (info.managing == STATUS.LIQUIDITYTOKEN) {
(bool reg, uint256 index) = indexInRegistry(info.toPermit, STATUS.RESERVETOKEN);
if (reg) {
delete registry[STATUS.RESERVETOKEN][index];
}
} else if (info.managing == STATUS.RESERVETOKEN) {
(bool reg, uint256 index) = indexInRegistry(info.toPermit, STATUS.LIQUIDITYTOKEN);
if (reg) {
delete registry[STATUS.LIQUIDITYTOKEN][index];
}
}

What is the purpose of queue/toggle in treasury?

Hey,

Could you please explain what is the purpose of queue/toggle in the Treasury contract ? Looks like it has been replaced by queueTimelock/execute in new version. I understand how it works, but I don't really understand what it's for?

I'm thinking that maybe it would allow the users of the protocol to anticipate the changes?

In addition, can you confirm that if blocksNeededForQueue=0 then this time locking mechanism becomes useless ?

Thanks!

LUSDAllocator could revert for wrong ethToLUSDRatio

The contract can revert if the set ethToLUSDRatio is set to above 1e6, which the contract currently allows.
The reversion would happen inside the uniswap v3 SwapRouter once not enough tokens are transferred, link.

Lines 92-95, 155 in LUSDAllocator.sol:

// line 92 - 95
    function setEthToLUSDRatio(uint256 _ethToLUSDRatio) external onlyGuardian {
        require(_ethToLUSDRatio <= 100 * FEE_PRECISION, "Value must be between 0 and 100 * 1e6");
        ethToLUSDRatio = _ethToLUSDRatio;
    }
// line 155           
    if (ethToLUSDRatio > 0 && ethToLUSDRatio <= (100 * FEE_PRECISION)) {

Line 93 should be changed to FEE_PRECISION, and if the fee can't be set through other functions then the check at line 155 is redundant and should be removed.

Testing gOHM on rinkeby

HI

I writing automated solution for Olympus Staking/Unstaking and trading. How do I get test OHM on Rinkeby network?
Do you have a link to a faucet?

Thanks and best regards.

Incorrect distribute amount when stake triggers rebase

Hello, ohmies!

I seem to have found a bug in staking.sol

When stake transaction triggers rebase the following is happening:

  1. First the staking contract transfers OHM from a user to itself
    OHM.safeTransferFrom(msg.sender, address(this), _amount);
  2. Then on the next line rebase is triggered
    _amount = _amount.add(rebase()); // add bounty if rebase occurred
  3. The Distributor contract mints new OHMs to staking contract
    distributor.distribute();
  4. And lastly the distribute amount is set for the next epoch.
    epoch.distribute = balance.sub(staked).sub(bounty);

The bug is in the last step. Because the staking contract transferred the user's OHMs before triggering rebase (see step 1) it impacts the distribution amount. So instead of equal to minted OHM amount of sOHM to be distributed in the next rebase it also includes the user's stake therefore OHM balance of the staking contract and sOHM circulation start slowly diverge.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.