Skip to content
Closed
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
39 changes: 39 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
on: [push]

name: hyperdrive

jobs:
check:
name: coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive

- name: install node
uses: actions/setup-node@v3
with:
node-version: 14.x

- name: install packages
uses: borales/actions-yarn@v4
with:
cmd: install # will run `yarn install` command
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} # if needed

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Run coverage
run: |
forge coverage --report lcov
sudo apt-get install lcov
lcov --remove lcov.info -o lcov.info 'test/*' 'script/*'

- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: "./lcov.info"
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
on: [push]

name: lint
name: hyperdrive

jobs:
build:
name: solidity
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
on: [push]

name: test
name: hyperdrive

jobs:
check:
name: solidity
name: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ node_modules/
yarn-error.log

.direnv

lcov.info
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[![Coverage Status](https://coveralls.io/repos/github/element-fi/hyperdrive/badge.svg?branch=via-ir-2&t=US78Aq)](https://coveralls.io/github/element-fi/hyperdrive?branch=via-ir-2)

# Hyperdrive

Hyperdrive is an automated market maker that enables fixed-rate markets to be
Expand Down Expand Up @@ -34,3 +36,5 @@ If you want to automatically format the code, run `yarn prettier`.

The language used in this codebase is for coding convenience only, and is not
intended to, and does not, have any particular legal or regulatory significance.

22cc2cx2qxw
44 changes: 26 additions & 18 deletions contracts/libraries/HyperdriveMath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,18 @@ library HyperdriveMath {
// timeRemaining*amountIn shares to purchase newly minted bonds on a
// YieldSpace curve configured to timeRemaining = 1.
uint256 curveIn = _amountIn.mulDown(_timeRemaining);

// Credit the share reserves by the flat trade.
_shareReserves = _shareReserves.add(flat);
// Debit the bond reserves by the flat trade.
_bondReserves = _bondReserves.sub(flat.mulDown(_sharePrice));

uint256 curveOut = YieldSpaceMath.calculateOutGivenIn(
// Credit the share reserves by the flat trade.
_shareReserves.add(flat),
// Debit the bond reserves by the flat trade.
_bondReserves.sub(flat.mulDown(_sharePrice)),
_shareReserves,
_bondReserves,
_bondReserveAdjustment,
curveIn,
FixedPointMath.ONE_18,
_timeStretch,
FixedPointMath.ONE_18.sub(_timeStretch),
_sharePrice,
_initialSharePrice,
_isBondOut
Expand All @@ -162,15 +165,18 @@ library HyperdriveMath {
uint256 curveIn = _amountIn.mulDown(_timeRemaining).divDown(
_sharePrice
);

// Debit the share reserves by the flat trade.
_shareReserves = _shareReserves.sub(flat);
// Credit the bond reserves by the flat trade.
_bondReserves = _bondReserves.add(flat.mulDown(_sharePrice));

uint256 curveOut = YieldSpaceMath.calculateOutGivenIn(
// Debit the share reserves by the flat trade.
_shareReserves.sub(flat),
// Credit the bond reserves by the flat trade.
_bondReserves.add(flat.mulDown(_sharePrice)),
_shareReserves,
_bondReserves,
_bondReserveAdjustment,
curveIn,
FixedPointMath.ONE_18,
_timeStretch,
FixedPointMath.ONE_18.sub(_timeStretch),
_sharePrice,
_initialSharePrice,
_isBondOut
Expand Down Expand Up @@ -230,15 +236,17 @@ library HyperdriveMath {
uint256 curveOut = _amountOut.mulDown(_timeRemaining).divDown(
_sharePrice
);

// Credit the share reserves by the flat trade.
_shareReserves = _shareReserves.add(flat);
// Debit the bond reserves by the flat trade.
_bondReserves = _bondReserves.sub(flat.mulDown(_sharePrice));
uint256 curveIn = YieldSpaceMath.calculateInGivenOut(
// Credit the share reserves by the flat trade.
_shareReserves.add(flat),
// Debit the bond reserves by the flat trade.
_bondReserves.sub(flat.mulDown(_sharePrice)),
_shareReserves,
_bondReserves,
_bondReserveAdjustment,
curveOut,
FixedPointMath.ONE_18,
_timeStretch,
FixedPointMath.ONE_18.sub(_timeStretch),
_sharePrice,
_initialSharePrice,
false
Expand Down
123 changes: 41 additions & 82 deletions contracts/libraries/YieldSpaceMath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ library YieldSpaceMath {
/// @param bondReserves bond reserves amount, unit is the face value in underlying
/// @param bondReserveAdjustment An optional adjustment to the reserve which MUST have units of underlying.
/// @param amountIn amount to be traded, if bonds in the unit is underlying, if shares in the unit is shares
/// @param t time till maturity in seconds
/// @param s time stretch coefficient. e.g. 25 years in seconds
/// @param oneMinusT 1 - st
/// @param c price of shares in terms of their base
/// @param mu Normalization factor -- starts as c at initialization
/// @param isBondOut determines if the output is bond or shares
Expand All @@ -30,56 +29,31 @@ library YieldSpaceMath {
uint256 bondReserves,
uint256 bondReserveAdjustment,
uint256 amountIn,
uint256 t,
uint256 s,
uint256 oneMinusT,
uint256 c,
uint256 mu,
bool isBondOut
) internal pure returns (uint256 result) {
uint256 outReserves;
uint256 rhs;
// Notes: 1 >= 1-st >= 0
uint256 oneMinusT = FixedPointMath.ONE_18.sub(s.mulDown(t));
// c/mu
) internal pure returns (uint256) {
uint256 cDivMu = c.divDown(mu);
// Adjust the bond reserve, optionally shifts the curve around the inflection point
uint256 modifiedBondReserves = bondReserves.add(bondReserveAdjustment);
// c/mu * (mu*shareReserves)^(1-t) + bondReserves^(1-t)
uint256 k = cDivMu
.mulDown(mu.mulDown(shareReserves).pow(oneMinusT))
.add(modifiedBondReserves.pow(oneMinusT));

bondReserves = bondReserves.add(bondReserveAdjustment);
uint256 k = _k(cDivMu, mu, shareReserves, oneMinusT, bondReserves);
if (isBondOut) {
// bondOut = bondReserves - ( c/mu * (mu*shareReserves)^(1-t) + bondReserves^(1-t) - c/mu * (mu*(shareReserves + shareIn))^(1-t) )^(1 / (1 - t))
outReserves = modifiedBondReserves;
// (mu*(shareReserves + amountIn))^(1-t)
uint256 newScaledShareReserves = mu
.mulDown(shareReserves.add(amountIn))
.pow(oneMinusT);
// c/mu * (mu*(shareReserves + amountIn))^(1-t)
newScaledShareReserves = cDivMu.mulDown(newScaledShareReserves);
// Notes: k - newScaledShareReserves >= 0 to avoid a complex number
// ( c/mu * (mu*shareReserves)^(1-t) + bondReserves^(1-t) - c/mu * (mu*(shareReserves + amountIn))^(1-t) )^(1 / (1 - t))
rhs = k.sub(newScaledShareReserves).pow(
shareReserves = mu.mulDown(shareReserves.add(amountIn)).pow(
oneMinusT
);
shareReserves = cDivMu.mulDown(shareReserves);
uint256 rhs = k.sub(shareReserves).pow(
FixedPointMath.ONE_18.divDown(oneMinusT)
);
return bondReserves.sub(rhs);
} else {
// shareOut = shareReserves - [ ( c/mu * (mu * shareReserves)^(1-t) + bondReserves^(1-t) - (bondReserves + bondIn)^(1-t) ) / c/u ]^(1 / (1 - t)) / mu
outReserves = shareReserves;
// (bondReserves + bondIn)^(1-t)
uint256 newScaledBondReserves = modifiedBondReserves
.add(amountIn)
.pow(oneMinusT);
// Notes: k - newScaledBondReserves >= 0 to avoid a complex number
// [( (mu * shareReserves)^(1-t) + bondReserves^(1-t) - (bondReserves + bondIn)^(1-t) ) / c/u ]^(1 / (1 - t))
rhs = k.sub(newScaledBondReserves).divDown(cDivMu).pow(
bondReserves = bondReserves.add(amountIn).pow(oneMinusT);
uint256 rhs = k.sub(bondReserves).divDown(cDivMu).pow(
FixedPointMath.ONE_18.divDown(oneMinusT)
);
// [( (mu * shareReserves)^(1-t) + bondReserves^(1-t) - (bondReserves + bondIn)^(1-t) ) / c/u ]^(1 / (1 - t)) / mu
rhs = rhs.divDown(mu);
return shareReserves.sub(rhs);
}
// Notes: outReserves - rhs >= 0, but i think avoiding a complex number in the step above ensures this never happens
result = outReserves.sub(rhs);
}

/// @dev Calculates the amount of an asset that will be received given a
Expand All @@ -88,8 +62,7 @@ library YieldSpaceMath {
/// @param bondReserves bond reserves amount, unit is the face value in underlying
/// @param bondReserveAdjustment An optional adjustment to the reserve which MUST have units of underlying.
/// @param amountOut amount to be received, if bonds in the unit is underlying, if shares in the unit is shares
/// @param t time till maturity in seconds
/// @param s time stretch coefficient. e.g. 25 years in seconds
/// @param oneMinusT 1 - st
/// @param c price of shares in terms of their base
/// @param mu Normalization factor -- starts as c at initialization
/// @param isBondIn determines if the input is bond or shares
Expand All @@ -99,57 +72,43 @@ library YieldSpaceMath {
uint256 bondReserves,
uint256 bondReserveAdjustment,
uint256 amountOut,
uint256 t,
uint256 s,
uint256 oneMinusT,
uint256 c,
uint256 mu,
bool isBondIn
) internal pure returns (uint256 result) {
uint256 inReserves;
uint256 rhs;
// Notes: 1 >= 1-st >= 0
uint256 oneMinusT = FixedPointMath.ONE_18.sub(s.mulDown(t));
// c/mu
) internal pure returns (uint256) {
uint256 cDivMu = c.divDown(mu);
// Adjust the bond reserve, optionally shifts the curve around the inflection point
uint256 modifiedBondReserves = bondReserves.add(bondReserveAdjustment);
// c/mu * (mu*shareReserves)^(1-t) + bondReserves^(1-t)
uint256 k = cDivMu
.mulDown(mu.mulDown(shareReserves).pow(oneMinusT))
.add(modifiedBondReserves.pow(oneMinusT));

bondReserves = bondReserves.add(bondReserveAdjustment);
uint256 k = _k(cDivMu, mu, shareReserves, oneMinusT, bondReserves);
if (isBondIn) {
// bondIn = ( c/mu * (mu*shareReserves)^(1-t) + bondReserves^(1-t) - c/mu * (mu*(shareReserves - shareOut))^(1-t) )^(1 / (1 - t)) - bond_reserves
inReserves = modifiedBondReserves;
// (mu*(shareReserves - amountOut))^(1-t)
uint256 newScaledShareReserves = mu
.mulDown(shareReserves.sub(amountOut))
.pow(oneMinusT);
// c/mu * (mu*(shareReserves - amountOut))^(1-t)
newScaledShareReserves = cDivMu.mulDown(newScaledShareReserves);
// Notes: k - newScaledShareReserves >= 0 to avoid a complex number
// ( c/mu * (mu*shareReserves)^(1-t) + bondReserves^(1-t) - c/mu * (mu*(shareReserves - amountOut))^(1-t) )^(1 / (1 - t))
rhs = k.sub(newScaledShareReserves).pow(
shareReserves = mu.mulDown(shareReserves.sub(amountOut)).pow(
oneMinusT
);
shareReserves = cDivMu.mulDown(shareReserves);
uint256 rhs = k.sub(shareReserves).pow(
FixedPointMath.ONE_18.divDown(oneMinusT)
);
return rhs.sub(bondReserves);
} else {
// shareOut = [ ( c/mu * (mu * shareReserves)^(1-t) + bondReserves^(1-t) - (bondReserves - bondOut)^(1-t) ) / c/u ]^(1 / (1 - t)) / mu - share_reserves
inReserves = shareReserves;
// (bondReserves - amountOut)^(1-t)
uint256 newScaledBondReserves = modifiedBondReserves
.sub(amountOut)
.pow(oneMinusT);
// Notes: k - newScaledBondReserves >= 0 to avoid a complex number
// [( (mu * shareReserves)^(1-t) + bondReserves^(1-t) - (bondReserves - amountOut)^(1-t) ) / c/u ]^(1 / (1 - t))
rhs = k.sub(newScaledBondReserves).divDown(cDivMu).pow(
bondReserves = bondReserves.sub(amountOut).pow(oneMinusT);
uint256 rhs = k.sub(bondReserves).divDown(cDivMu).pow(
FixedPointMath.ONE_18.divDown(oneMinusT)
);
// [( (mu * shareReserves)^(1-t) + bondReserves^(1-t) - (bondReserves - amountOut)^(1-t) ) / c/u ]^(1 / (1 - t)) / mu
rhs = rhs.divDown(mu);
return rhs.sub(shareReserves);
}
// TODO: Double check this.
//
// Notes: rhs - inReserves >= 0, but i think avoiding a complex number in the step above ensures this never happens
result = rhs.sub(inReserves);
}

function _k(
uint256 cDivMu,
uint256 mu,
uint256 shareReserves,
uint256 oneMinusT,
uint256 modifiedBondReserves
) private pure returns (uint256) {
return
cDivMu.mulDown(mu.mulDown(shareReserves).pow(oneMinusT)).add(
modifiedBondReserves.pow(oneMinusT)
);
}
}
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ optimizer = true
# The number of optimizer runs
optimizer_runs = 7500
# Whether or not to use the Yul intermediate representation compilation pipeline
via_ir = true
via_ir = false

remappings = ['forge-std=lib/forge-std/src', '@openzeppelin/=node_modules/@openzeppelin']
# gas limit - max u64
Expand Down
6 changes: 2 additions & 4 deletions test/YieldSpaceMath.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ contract YieldSpaceMathTest is Test {
62.38101813e18, // bondReserves
119.1741606776616e18, // bondReserveAdjustment
5.03176076e18, // amountOut
0.08065076081220067e18, // t
1e18, // s
1e18 - 0.08065076081220067e18, // t
1e18, // c
1e18, // mu
true // isBondIn
Expand All @@ -29,8 +28,7 @@ contract YieldSpaceMathTest is Test {
56.92761678068477e18, // bondReserves
119.1741606776616e18, // bondReserveAdjustment
5.500250311701939e18, // amountOut
0.08065076081220067e18, // t
1e18, // s
1e18 - 0.08065076081220067e18, // t
1e18, // c
1e18, // mu
false // isBondIn
Expand Down