Coder Social home page Coder Social logo

umaprotocol / protocol Goto Github PK

View Code? Open in Web Editor NEW
364.0 21.0 177.0 49.95 MB

UMA Protocol Running on Ethereum

Home Page: https://uma.xyz

License: GNU Affero General Public License v3.0

JavaScript 51.08% Solidity 20.13% Shell 0.41% Dockerfile 0.02% TypeScript 28.36%
defi ethereum monorepo

protocol's Introduction

UMA Protocol

UMA Logo

<UMAprotocol> Docker Cloud Build Status Coverage Status

GitHub GitHub last commit GitHub commit activity GitHub contributors

Generic badge Generic badge Generic badge Twitter Follow

Documentation ๐Ÿ“š

Our docs site is here. It contains tutorials, explainers, and smart contract documentation. If you'd like to view these docs on github instead, check out the documentation folder in the docs repo.

Security and Bug Bounty ๐Ÿ›

Please see here for details on our bug bounty.

Contributing ๐Ÿ™Œ

Please see our contributing guidelines.

Developer Information and Tools ๐Ÿ‘ฉโ€๐Ÿ’ป

For detailed information on how to initialize and interact with our smart contracts, please see the documentation site.

Install dependencies ๐Ÿ‘ทโ€โ™‚๏ธ

You'll need to install the long-term support version of nodejs, currently nodejs v20. You will also need to install yarn. Assuming that's done, run yarn with no args:

yarn

If you'd like to completely clear all packages' node_modules and reinstall all deps from scratch, run:

yarn clean-packages
yarn

Build the code ๐Ÿง

Some code in the repository requires a build step to compile it. To run this build step, use the qbuild (quick build) command:

yarn qbuild

The above command does not include dapps because dapps take a long time to build and they have their own scripts to run locally. However, if you'd like to build everything, you can use the build command:

yarn build

To remove any remnants of previous builds, you can run:

yarn clean

Run tests ๐Ÿฆพ

To run tests, you'll need to start ganache on port 9545:

yarn ganache-cli -e 1000000000 -p 9545 -l 9000000 -d

Note: if you're interested in what these args do:

  • -e is the amount of ETH to grant the default accounts.
  • -p is the port that ganache will listen on.
  • -d tells ganache to use a standard set of deterministic accounts on each run.

Then, you can run all of the tests across the repo by running:

yarn test

However, running all of the tests across the repository takes a lot of time. To run the tests for just one package, you can run:

yarn workspace <package_name> test

Running the linter ๐Ÿงฝ

To run the linter in autofix mode (it will attempt to fix any errors it finds), run:

yarn lint-fix

To run the linter in the default mode, where it will print all errors and not modify code, run:

yarn lint

Packages ๐Ÿ“ฆ

Because this repo is a monorepo, it contains many different npm packages. More will be discussed about these packages in the following sections. However, the basic structure is that each package is listed in the packages/ directory. Each package has its own scripts and dependencies and operates (mostly) independently from the others.

Adding dependencies ๐Ÿ‘ฉโ€๐Ÿ‘ฆ

All runtime/production dependencies should be added to the package that needs them. Development dependencies should also generally be installed in packages unless they are needed by code that exists outside of any package.

For more details on packages and the monorepo, please see the next section.

To add a dependency to a package:

yarn workspace <package_name> add <dependency_name>

Note: development dependencies are those that are not required by the code that's published to the npm registry. If you're not sure whether a dependency should be dev or not, just ask! To install a dev dependency in a package:

yarn workspace <package_name> add <dependency_name> --dev

Note: all root dependencies should be dev dependencies because the root package is not published to npm, so there is no "production" code. To install a dev dependency at root:

yarn add <dependency_name> --dev

After you've installed a dependency, yarn should automatically update the yarn.lock file. If git doesn't notice any changes in that file, run yarn to update the lockfile.

Depending on another package in the monorepo ๐Ÿค

The standard way to pull a JS element from another package is to reference it like this:

const { importedObject } = require("@uma/some-package")

Note: the require will resolve to the main file specified in the package.json file. If you'd like to import a different file, you should ensure that that file is exported in the files directive inside the package.json file. Once you're sure of that, you can import it using the following syntax:

const { importedObject } = require("@uma/some-package/path/to/some/file")

Note: if this file isn't exported by the files directive, it will work locally, but fail when run via an npm installation.

To install this dependency you're using in @uma/my-package, you should run the following command:

yarn lerna add @uma/some-package --scope @uma/my-package

By default, this will symlink the package in node_modules rather than attempting to pull the package via npm. This allows the packages to depend on the in-repo versions of one another. If you'd like to reference a particular version from npm, you can specify that version exactly in the package.json file.

Using yarn and lerna ๐Ÿง‘โ€๐Ÿณ

This repository is a monorepo. That means that it contains many different, but related packages. It uses yarn workspaces and lerna to manage these packages.

Note: lerna and yarn workspaces have some overlapping functionality. This is because lerna predates yarn workspaces and is compatible with yarn alternatives that don't have workspace functions, like npm.

yarn should be installed globally to use this repo. This means that you can run any yarn command by running:

yarn <command>

Once you run yarn during the install section above, lerna should have been installed locally. After that, you should be able to run lerna commands using yarn:

yarn lerna <command>

To run a yarn command in a particular sub-package, you can run the following from anywhere in the repo:

yarn workspace <package_name> <script>

For instance, this could be used to run the build command in the @uma/core package:

yarn workspace @uma/core build

or to install the truffle package as a devDependency in the @uma/liquidator package:

yarn workspace @uma/liquidator add truffle --dev

To run a package script in every package that has a script by that name, you should use lerna:

yarn lerna run <script> --stream

Note: the stream argument is just to force lerna to stream the output so you get realtime logs, but it's not required.

Coverage ๐Ÿ”Ž

We use the solidity-coverage package to generate our coverage reports. You can find the coverage report at coveralls. Otherwise, you can generate it locally by running:

./ci/coverage.sh packages/core

The full report can be viewed by opening the packages/core/coverage/index.html file in a browser.

Style Guide ๐Ÿ•บ

See STYLE.md.

protocol's People

Contributors

abg4 avatar adrianmcli avatar akshaysrivastav avatar allisonlu22 avatar amateima avatar bryanjcampbell1 avatar cc7768 avatar chrismaree avatar daywiss avatar dependabot[bot] avatar edouardlvdl avatar evaldofelipe avatar freshmanq avatar hlambur avatar jaxrtech avatar kendricktan avatar kevinuma avatar md0x avatar mrice32 avatar nicholaspai avatar pemulis avatar ptare avatar pumpedlunch avatar pxrl avatar rcai1 avatar reinis-frp avatar rosalindstengle avatar schystz avatar smb2796 avatar uma-mining 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

protocol's Issues

Handle expiry and settlement agreement

We are currently not getting the NPV precisely at the expiry, and we are not implementing the "agree to settle logic". Once expired, each party can withdraw their entire balance. We should implement expiry NPV calculation (unverified price), agree to settle (unverified expiry price), and auto settlement on the verified price. This depends on a separation of verified and unverified feeds discussed in #12.

Redo defaults logic

Now that we're using structs that keep information in a cleaner way, we should rewrite the whoDefaults function to be a little less clunky.

Update Registry API

bool isDerivativeRegistered(address)

  • This method returns true if the contract is registered and false if it is not.

array[(address creatorAddress, address derivativeAddress)] getRegisteredDerivatives(address counterparty)

  • Returns a list of all the derivatives that the counterparty is involved in.

bool isDerivativeCreatorAuthorized(address derivativeCreator)

  • Returns whether a derivative creator is authorized or not.

addContractCreator(address contractCreator)
removeDerivativeCreator(address contractCreator)

  • These methods add and remove derivative creators from the list of authorized derivative creators that are allowed to register contracts.
  • Only the owner (Oracle) can call these methods

registerDerivative(array[address] counterparties, address derivativeAddress)

  • Registers a new derivative.
  • Only an authorized derivative creator can call this method.

Implement a centralized oracle

Implement a centralized oracle to work within the v0 oracle interface. Price requests should be resolved manually by a single owner.

Build a javascript date conversion library

We end up needing to convert between Solidity timestamps and javascript dates often. It would be nice to construct a simple javascript library to do this conversion as well as some of our common operations on the javascript dates (like creating date object with a user provided date, but application provided time on that date).

Test Cases

  • Contract creation
  • Deposit
  • Start contract once enough margin is included on both sides
  • Remargin correct
  • Test balances when they drop negative and ensure person can't withdraw "too much"
  • Settle with confirmed price
  • Settle with verified price

Add CI to PR process

We should set up a CI system that verifies that PRs build and pass tests (once we write them :) ).

Implement dispute logic

We need to implement a dispute flow. Disputes can arise from Live, Expired, and Defaulted states IIRC. This depends on #12.

Clean up contract migrations

The contract migrations are currently a mess of mostly repeated .then() statements nested inside simple branches. This can probably be cleaned up to a more minimal, simplistic approach.

Add calcNAV method to TokenizedDerivative

The calcNAV method would be a view method that would allow one to calculate an updated NAV without actually updating the contract state. Optionally, it may make sense to add a calcRequiredMargin as well.

VoteCoin delays verified prices

VoteCoin currently does not allow verified prices to be published until the beginning of the next voting period, even if they have already been approved and voting has ended.

Write v0 oracle interface

The v0 interface should have a single method getPrice() that enqueues a price request to be resolved by the oracle at a later time or returns the value if it has already been resolved.

Build Price Scraper

Build a price scraper that pulls bitcoin prices and uploads them to the MockOracle.

Move our Solidity to a more Object Oriented approach

We are essentially using contracts as the only objects in our current programming paradigm. We can use inheritance to break up concern a bit, but this doesn't necessarily give us the power to do true object composition with more complex data structures. We should move to taking advantage of [using for] and libraries to create object-like structs.

Add a linter/format checker.

I don't think there are any auto formatters out for solidity (sadly). I think we should pick a linter that will check code format and look for simple issues. solhint appears to be relatively mature, has plugins for a bunch of IDEs, and it allows customization through configs and comments.

Meta: convert TODOs in code to GH issues.

We should convert all our TODOs in code to GH issues - I think this will make them a bit easier to track. We don't necessarily need to remove them form the code, but we can link to the in-code TODO from the issue.

New structs in derivative

Some of these structs were discussed and proposed in comments on #20

  • Struct with information about balance, address balance, whether price has been confirmed
  • etc...

Create price feed interface

Create the interface for external price feeds that allows users to access "unverified" price feeds. This will partially replace the OracleInterface being used now.

Build Fragmented Registry

There is a global size limit for contract bytecode in Ethereum. Because the bytecode of the contracts that the registry creates must be included in the registry's bytecode, we need to fragment the registry into multiple "creator" contracts that are allowed to register contracts that they create with the registry to ensure the Registry is "deployable".

Build Basic Tokenized Derivative Logic

We need to create a new TokenizedDerivative that allows one counterparty to provide "tokenized" exposure to the asset. The tokens can be authorized by the offering counterparty, created/bought by the investing counterparty, and redeemed for ETH by the investing counterparty.

  • Build Basic Logic
  • Add Tests

Clean up normal derivative (TRS) deployment

Normal derivative should be called TRS (or something similar), and its deployment should not assume one of the counterparties is the sender. All notation within the contract should be changed to long-short rather than the maker-taker notation currently used.

Gas usage regression tests

[Credit @cc7768] We should have some sort of regression tests that allow us to compare the gas costs of different function PR to PR. This blog post talks about some of the gotchas, methodology, and tradeoffs wrt optimizing for gas.

Try to remove time-based logic from contracts

In general, block.timestamp (or now) isn't particularly accurate and can be a security flaw if used carelessly. It's generally recommended that smart contracts avoid time based logic altogether (the solhint linter complains about this) in favor of block-number based logic, which can't be manipulated by the miner.

Time based attack analysis

We need to take a look through our contracts to ensure that there are no potential transaction reordering attacks. For example, in our swap contract, let's assume one party wants to dispute the current unverified price. They must make a deposit to do so (this is still a TODO). If the disputed price was correct, the counterparty receives the deposit. However, if the counterparty gets a remargin in before the dispute, the current price may change. Therefore, once the disputing party may not be disputing the price that they thought they were. For this reason, it makes sense to require them to pass the contract time point that they are trying to dispute. If the contract has moved past that time point, then the dispute gets reverted. These sorts of attacks are subtle, but important. Transaction ordering is determined by the miners based on many factors (one of which is the offered gas price), and it could also be exploited by miners with a vested interest in a particular order.

Add disputeNow() to TokenizedDerivative

disputeNow() allows a provider to dispute the price right now rather than at the last remargin time. This is necessary to ensure that a user can dispute a price feed that is no longer publishing prices. Open question: how does the contract determine if the dispute was correct and the deposit should be refunded?

Margin accounts and currency risk

Are we exclusively storing margin in ETH? It seems to be the default choice because of its relative stability and its trustworthiness when compared to other crypto assets/stablecoins. I may be operating on outdated or incorrect info, so feel free to correct me.

In any case, storing margin in ETH presents some currency risk to participants, and they would likely want to hedge out that risk. This sort of margin currency issue is probably a familiar one in financial circles. However, I would guess that the volatility of our margin currency and the relative difficulty of getting short exposure to crypto might mean that a common flow would be to create two swaps at once - one for the original swap and a second to translate the margin risk into a currency that each party feels more comfortable holding. Does this sound right to y'all? Or am I missing something? I'm not sure if there's anything actionable here other than the fact that we may want to build our contracts/tutorials/docs with this use case in mind.

Also, this presents the issue of how to set margin requirements. If the swap, itself, has nothing directly to do with ETH, we may want to encode the relative value of ETH in the margin requirements to ensure a severe drop or increase in the value of ETH doesn't cause the effective margin requirement to vary wildly. Thoughts?

cc @hlambur @allisonlu22 @cc7768 @sglyon

Add Dapp controller functionality to TokenizedDerivative

The Dapp controller method should essentially combine the authorizeTokens() and createTokens() methods to allow a user, if their address matches both the investor and provider, to do both with a single method call. This method should have the following basic structure:

function authorizeAndCreateTokens(uint tokenNavToCreate) external payable onlyProvider onlyInvestor
{
    ...
} 

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.