Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audit/testing cleanup #131

Merged
merged 11 commits into from
Jan 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name: test

jobs:
check:
name: Foundry project
name: Hyper Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand Down
7 changes: 4 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/solstat"]
path = lib/solstat
url = https://github.com/primitivefinance/solstat
[submodule "lib/solmate"]
path = lib/solmate
url = https://github.com/transmissions11/solmate
branch = v7
[submodule "lib/solstat"]
path = lib/solstat
url = https://github.com/primitivefinance/solstat
branch = beta-v0.0.1
423 changes: 205 additions & 218 deletions LICENSE

Large diffs are not rendered by default.

109 changes: 49 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,60 +1,49 @@
# Primitive Hyper RMM

Full vision of Primitive Replicating Market Maker.

## Notes

- [x] Investigate use of msg.value! (used in fund).
- [x] Improve/fix swap. Assigned to Clement.
- [ ] Investigate gas costs of swaps.
- [x] Investigate curve/pair nonces. Assigned to Alex.
- [ ] Add utility functions to fetch all data. Assigned to Alex.
- [ ] Add random swaps to invariant testing.
- [ ] Investigate typecasting.
- [ ] Investiate assembly usage.
- [ ] Explore refactor of free functions. I like free functions but they are so new that not many testing frameworks have good support yet.
- [ ] Explore implications of time movement creating price changes. Cannot change price and liquidity at the same time, thats an invariant!

#### Allocate

Adding liquidity increases pool and position liquidity balances, and charges the caller the virtual balances of tokens required to back that liquidity.

Virtual balances depend on price.

Price should not change when adding liquidity.

If liquidity changes, virtual balances need to be updated, which would require tokens to be paid to the contract.

Changing a position:

- Timestamp synced
- Fees are synced
- Position Liquidity is touched
- Pool is touched
- Reserves are touched

#### Notes

- Increasing reserves but paying entirely with internal balance leads to a deficit and therefore invariant failure.
- Be careful about `storage` or `memory` when using the library types. If a pool is computing important values, it should always be from storage, else it might not have the updates in the transaction. There was a bug where I was using the `lastTau` method on a pool in memory, and this was not updated even though the same `storage` pool was updated.
- Unbounded loops in free functions (for view ones at least) will revert with "EVM Error: Stack overflow"
- For tokens with lower decimals, there is a minimum amount of liquidity that can be allocated/removed. This is because liquidity is in WAD units while token amounts could be smaller, if they have low decimals.

## todo

- [x] Fix tests, especially swaps.
- [x] Solstat tests. - sunday
- [x] Refactor accounting system!
- [ ] Work on docs 1 pager for auditor - monday
- [ ] Light gas analysis/optimization - none
- [x] Finish stake/unstake - sunday
- [x] Add parameter validation to changeParameters function
- [x] Rename HyperLib to HyperLib ?
- [x] TOKEN DECIMALS NOT HANDLED
- [x] Claim fees working and tested
- [ ] Investigate price movements by swap.
- [x] Finish SIMPLE stake.
- [ ] Final cleanup of all console and logging.
- [ ] Better swap tests.
- [ ] Better account system tests.
- [ ] Add priority fee growth for WETH only.
# Primitive Hyper

Hyper is a replicating market maker.

## System Invariants

The system is designed around a single invariant:

```
Balance >= Reserve
```

Exposed via: `hyper.getNetBalance(token)`

For more invariants, [read this](./test/README.md).

## Installation

Required:

- Foundry
- Ganache
- Node >=v16.x
- Python (if running echidna)

### 1. Install foundry. [source](https://github.com/foundry-rs/foundry)

`curl -L https://foundry.paradigm.xyz | bash`

### 2. Restart terminal or reload `PATH`, then run:

`foundryup`

### 3. Install deps

`forge install`

### 4. Test

`yarn test`

## Resources

- [RMM in desmos](https://www.desmos.com/calculator/8py0nzdgfp)
- [Original codebase](https://github.com/primitivefinance/rmm-core)
- [solstat](https://github.com/primitivefinance/solstat)
- [Replicating Market Makers](https://github.com/angeris/angeris.github.io/blob/master/papers/rmms.pdf)
- [RMM whitepaper](https://primitive.xyz/whitepaper)
- [High precision calculator](https://keisan.casio.com/calculator)
2 changes: 1 addition & 1 deletion contracts/Assembly.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-3.0-only
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.13;

/**
Expand Down
2 changes: 1 addition & 1 deletion contracts/Enigma.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-3.0-only
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.13;

/**
Expand Down
18 changes: 9 additions & 9 deletions contracts/Hyper.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: UNLICENSED
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.13;

/**
Expand Down Expand Up @@ -529,8 +529,8 @@ contract Hyper is IHyper {

uint passed = getTimePassed(poolId);
if (passed > 0) {
uint256 tau = pool.lastTau(); // uses pool's last update timestamp.
(price, tick) = pool.computePriceChangeWithTime(tau, passed);
uint256 lastTau = pool.lastTau(); // uses pool's last update timestamp.
(price, tick) = pool.computePriceChangeWithTime(lastTau, passed);
}
}

Expand Down Expand Up @@ -614,19 +614,19 @@ contract Hyper is IHyper {
pool.lastTimestamp = timestamp;
pool.lastPrice = price;
pool.lastTick = Price.computeTickWithPrice(pool.lastPrice);
bool isMutable = pool.controller != address(0);
if (isMutable && priorityFee == 0) revert InvalidFee(priorityFee); // Cannot set priority to 0.
bool hasController = pool.controller != address(0);
if (hasController && priorityFee == 0) revert InvalidFee(priorityFee); // Cannot set priority to 0.

uint24 pairNonce = pairId == 0 ? uint24(getPairNonce) : pairId; // magic variable
pool.pair = pairs[pairNonce];

HyperCurve memory params = HyperCurve({
maxTick: max,
jit: isMutable ? jit : uint8(_liquidityPolicy()),
jit: hasController ? jit : uint8(_liquidityPolicy()),
fee: fee,
duration: dur,
volatility: vol,
priorityFee: isMutable ? priorityFee : 0, // min fee
priorityFee: hasController ? priorityFee : 0, // min fee
createdAt: timestamp
});
params.validateParameters();
Expand All @@ -637,12 +637,12 @@ contract Hyper is IHyper {
poolNonce = uint32(++getPoolNonce);
}

poolId = Enigma.encodePoolId(pairNonce, isMutable, poolNonce);
poolId = Enigma.encodePoolId(pairNonce, hasController, poolNonce);
if (pools[poolId].exists()) revert PoolExists();

pools[poolId] = pool; // effect

emit CreatePool(poolId, isMutable, pool.pair.tokenAsset, pool.pair.tokenQuote, price);
emit CreatePool(poolId, hasController, pool.pair.tokenAsset, pool.pair.tokenQuote, price);
}

function changeParameters(
Expand Down
12 changes: 6 additions & 6 deletions contracts/HyperLib.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: UNLICENSED
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.13;

/**
Expand Down Expand Up @@ -284,11 +284,11 @@ function getAmountsWad(HyperPool memory self) view returns (uint amountAssetWad,

function computePriceChangeWithTime(
HyperPool memory self,
uint tau,
uint timeRemaining,
uint epsilon
) pure returns (uint price, int24 tick) {
uint strike = Price.computePriceWithTick(self.params.maxTick);
price = Price.computePriceWithChangeInTau(strike, self.params.volatility, self.lastPrice, tau, epsilon);
uint maxPrice = Price.computePriceWithTick(self.params.maxTick);
price = Price.computePriceWithChangeInTau(maxPrice, self.params.volatility, self.lastPrice, timeRemaining, epsilon);
tick = Price.computeTickWithPrice(price);
}

Expand All @@ -308,7 +308,7 @@ function getRMM(HyperPool memory self) view returns (Price.RMM memory) {
return Price.RMM({strike: self.params.strike(), sigma: self.params.volatility, tau: self.lastTau()});
}

function lastTau(HyperPool memory self) view returns (uint tau) {
function lastTau(HyperPool memory self) view returns (uint) {
return self.tau(self.lastTimestamp);
}

Expand All @@ -318,7 +318,7 @@ function tau(HyperPool memory self, uint timestamp) view returns (uint) {
return end - timestamp;
}

function strike(HyperCurve memory self) view returns (uint strike) {
function strike(HyperCurve memory self) view returns (uint) {
return Price.computePriceWithTick(self.maxTick);
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/OS.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-3.0-only
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.13;

/**
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/IHyper.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: UNLICENSED
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.13;

import {HyperCurve, HyperPair} from "../HyperLib.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/IWETH.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: UNLICENSED
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

interface IWETH {
Expand Down
Loading