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

Very simple deposit/withdraw logic and share accounting #3

Merged
merged 27 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7ac7bd5
Very simple deposit/withdraw logic and share accounting
mcclurejt Aug 7, 2024
d086ea7
reformat second-level comments
mcclurejt Aug 7, 2024
6b3d5b2
redeem override + comment updates + contribution guide
mcclurejt Aug 7, 2024
07c4105
update contract version to 0.8.22 and relax lib/interface/test versions
mcclurejt Aug 7, 2024
dcb7b43
remove redundant comment
mcclurejt Aug 7, 2024
207a691
cleanup Everlong unit test
mcclurejt Aug 7, 2024
5ad7f29
fix Everlong test comment
mcclurejt Aug 7, 2024
a5f9e5b
maxDeposit functionality/tests and comment cleanup
mcclurejt Aug 8, 2024
0546155
remove unused test helper
mcclurejt Aug 8, 2024
4bac426
addressing feedback: remove unnecessary approval + deposit override
mcclurejt Aug 22, 2024
39153e1
addressing feedback: `redeem()` commenting
mcclurejt Aug 22, 2024
b7db8ca
addressing feedback: _beforeWithdraw virtual assets commenting + todo
mcclurejt Aug 22, 2024
4cc4951
addressing feedback: kind/version tests
mcclurejt Aug 23, 2024
dea4d2b
Update test/units/EverlongERC4626.t.sol
mcclurejt Aug 23, 2024
97f7523
addressing feedback: refactor contracts to more "flat" structure (cur…
mcclurejt Aug 23, 2024
bf17ef3
addressing feedback: remove IEverlong from Everlong inheritance
mcclurejt Aug 25, 2024
cfcf9c5
addressing feedback: remove duplicated test + clean up inheritance
mcclurejt Aug 26, 2024
cc984ff
_rebalance() visibility
mcclurejt Aug 26, 2024
8875360
addressing feedback: immutable decimals + fix `_increaseIdle` logic +…
mcclurejt Aug 26, 2024
d49b040
variable reordering
mcclurejt Aug 26, 2024
bf4a2e1
file casing import fix
mcclurejt Aug 26, 2024
9969f42
Update contracts/internal/EverlongPositions.sol
mcclurejt Aug 27, 2024
8d6f178
Update contracts/internal/EverlongPositions.sol
mcclurejt Aug 27, 2024
4de9b56
Update contracts/internal/EverlongPositions.sol
mcclurejt Aug 27, 2024
84bbb0c
Update test/exposed/EverlongExposed.sol
mcclurejt Aug 27, 2024
41326d1
Update test/exposed/EverlongERC4626Exposed.sol
mcclurejt Aug 27, 2024
937307d
addressing feedback: asBase public function
mcclurejt Aug 27, 2024
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
1 change: 1 addition & 0 deletions .solhint.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"rules": {
"func-name-mixedcase": "off",
"var-name-mixedcase": "off",
"immutable-vars-naming": "off",
"no-unused-vars": "error"
}
}
12 changes: 12 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Contributing to Everlong

## Bugfixes & issues

If you find a bug, we recommend that you post an [issue](https://github.com/delvtech/everlong/issues) to allow for discussion before creating a pull request.

## Release steps

1. [ ] Double-check that the version in `contracts/libraries/Constants.sol` matches the version to be tagged. If it doesn't, open a PR to update the version before tagging.
2. [ ] Tag the release with `git tag vX.Y.Z`.
3. [ ] Push the release to Github with `git push --tags`
4. [ ] Go to the `releases` tab in Github and add the new tag as a release. Click the "Generate Release Notes" button to generate release notes.
72 changes: 62 additions & 10 deletions contracts/Everlong.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.20;
pragma solidity 0.8.22;

import { IHyperdrive } from "hyperdrive/contracts/src/interfaces/IHyperdrive.sol";
import { IEverlong } from "./interfaces/IEverlong.sol";
import { EverlongAdmin } from "./internal/EverlongAdmin.sol";
import { EverlongBase } from "./internal/EverlongBase.sol";
import { EverlongERC4626 } from "./internal/EverlongERC4626.sol";
import { EverlongPositions } from "./internal/EverlongPositions.sol";
import { EVERLONG_KIND, EVERLONG_VERSION } from "./libraries/Constants.sol";

/// ,---..-. .-.,---. ,---. ,-. .---. .-. .-. ,--,
/// | .-' \ \ / / | .-' | .-.\ | | / .-. ) | \| |.' .'
Expand Down Expand Up @@ -62,16 +66,64 @@ import { EverlongPositions } from "./internal/EverlongPositions.sol";
/// @custom:disclaimer The language used in this code is for coding convenience
/// only, and is not intended to, and does not, have any
/// particular legal or regulatory significance.
contract Everlong is EverlongAdmin, EverlongPositions {
/// @notice Initial configuration paramters for Everlong.
/// @param _name Name of the ERC20 token managed by Everlong.
/// @param _symbol Symbol of the ERC20 token managed by Everlong.
/// @param __hyperdrive Address of the Hyperdrive instance wrapped by Everlong.
/// @param __asBase Whether to use Hyperdrive's base token for bond purchases.
contract Everlong is EverlongAdmin, EverlongPositions, EverlongERC4626 {
// ╭─────────────────────────────────────────────────────────╮
// │ Constructor │
// ╰─────────────────────────────────────────────────────────╯

/// @notice Initial configuration paramters for EverlongERC4626.
/// @param __name Name of the ERC20 token managed by Everlong.
/// @param __symbol Symbol of the ERC20 token managed by Everlong.
/// @param __hyperdrive Address of the Hyperdrive instance.
/// @param __asBase Whether to use the base or shares token from Hyperdrive.
constructor(
string memory _name,
string memory _symbol,
string memory __name,
string memory __symbol,
address __hyperdrive,
bool __asBase
) EverlongBase(_name, _symbol, __hyperdrive, __asBase) {}
) {
// Store constructor parameters.
_name = __name;
_symbol = __symbol;
_hyperdrive = __hyperdrive;
_asBase = __asBase;
_asset = __asBase
? IHyperdrive(__hyperdrive).baseToken()
: IHyperdrive(__hyperdrive).vaultSharesToken();

// Set the admin to the contract deployer.
_admin = msg.sender;

// Attempt to retrieve the decimals from the {_asset} contract.
// If it does not implement `decimals() (uint256)`, use the default.
mcclurejt marked this conversation as resolved.
Show resolved Hide resolved
(bool success, uint8 result) = _tryGetAssetDecimals(_asset);
_decimals = success ? result : _DEFAULT_UNDERLYING_DECIMALS;
}

// ╭─────────────────────────────────────────────────────────╮
// │ Getters │
// ╰─────────────────────────────────────────────────────────╯

/// @notice Gets the Everlong instance's kind.
/// @return The Everlong instance's kind.
function kind() external view returns (string memory) {
return EVERLONG_KIND;
}

/// @notice Gets the Everlong instance's version.
/// @return The Everlong instance's version.
function version() external view returns (string memory) {
return EVERLONG_VERSION;
}

/// @notice Gets the address of the underlying Hyperdrive Instance.
function hyperdrive() external view returns (address) {
return _hyperdrive;
}

/// @notice Gets whether Everlong uses Hyperdrive's base token to
/// transact.
function asBase() external view returns (bool) {
return _asBase;
}
}
10 changes: 7 additions & 3 deletions contracts/interfaces/IEverlong.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.20;
pragma solidity ^0.8.20;

import { IERC4626 } from "openzeppelin/interfaces/IERC4626.sol";
import { IEverlongAdmin } from "./IEverlongAdmin.sol";
Expand Down Expand Up @@ -31,12 +31,12 @@ interface IEverlong is
// │ Errors │
// ╰─────────────────────────────────────────────────────────╯

// Admin //
// ── Admin ──────────────────────────────────────────────────

/// @notice Thrown when caller is not the admin.
error Unauthorized();

// Positions //
// ── Positions ──────────────────────────────────────────────

/// @notice Thrown when attempting to insert a position with
/// a `maturityTime` sooner than the most recent position's.
Expand All @@ -45,4 +45,8 @@ interface IEverlong is
/// @notice Thrown when attempting to close a position with
/// a `bondAmount` greater than that contained by the position.
error InconsistentPositionBondAmount();

/// @notice Thrown when a target idle amount is too high to be reached
/// even after closing all positions.
error TargetIdleTooHigh();
}
2 changes: 1 addition & 1 deletion contracts/interfaces/IEverlongAdmin.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.20;
pragma solidity ^0.8.20;

interface IEverlongAdmin {
// ╭─────────────────────────────────────────────────────────╮
Expand Down
6 changes: 3 additions & 3 deletions contracts/interfaces/IEverlongEvents.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.20;
pragma solidity ^0.8.20;

interface IEverlongEvents {
// Admin //
// ── Admin ──────────────────────────────────────────────────

/// @notice Emitted when admin is transferred.
event AdminUpdated(address indexed admin);

// Positions //
// ── Positions ──────────────────────────────────────────────

/// @notice Emitted when a new position is added to the bond portfolio.
/// @dev This event will only be emitted with new `maturityTime`s in the portfolio.
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/IEverlongPositions.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.20;
pragma solidity ^0.8.20;

import { Position } from "../types/Position.sol";

Expand Down
4 changes: 2 additions & 2 deletions contracts/internal/EverlongAdmin.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.20;
pragma solidity 0.8.22;

import { IEverlong } from "../interfaces/IEverlong.sol";
import { IEverlongAdmin } from "../interfaces/IEverlongAdmin.sol";
import { EverlongBase } from "./EverlongBase.sol";
import { EverlongBase } from "../internal/EverlongBase.sol";

/// @author DELV
/// @title EverlongAdmin
Expand Down
87 changes: 13 additions & 74 deletions contracts/internal/EverlongBase.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.20;
pragma solidity 0.8.22;

import { IHyperdrive } from "hyperdrive/contracts/src/interfaces/IHyperdrive.sol";
import { DoubleEndedQueue } from "openzeppelin/utils/structs/DoubleEndedQueue.sol";
import { IERC20 } from "openzeppelin/interfaces/IERC20.sol";
import { IEverlongEvents } from "../interfaces/IEverlongEvents.sol";
import { EVERLONG_KIND, EVERLONG_VERSION } from "../libraries/Constants.sol";
import { EverlongERC4626 } from "./EverlongERC4626.sol";
import { EverlongStorage } from "./EverlongStorage.sol";

// TODO: Reassess whether centralized configuration management makes sense.
// https://github.com/delvtech/everlong/pull/2#discussion_r1703799747
Expand All @@ -16,79 +13,21 @@ import { EverlongERC4626 } from "./EverlongERC4626.sol";
/// @custom:disclaimer The language used in this code is for coding convenience
/// only, and is not intended to, and does not, have any
/// particular legal or regulatory significance.
abstract contract EverlongBase is EverlongERC4626, IEverlongEvents {
abstract contract EverlongBase is EverlongStorage, IEverlongEvents {
using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque;

// ╭─────────────────────────────────────────────────────────╮
// │ Storage
// │ Stateful
// ╰─────────────────────────────────────────────────────────╯

// Admin //
/// @dev Rebalances the Everlong bond portfolio if needed.
function _rebalance() internal virtual;

/// @dev Address of the contract admin.
address internal _admin;

// Hyperdrive //

/// @dev Address of the Hyperdrive instance wrapped by Everlong.
address public immutable hyperdrive;

/// @dev Whether to use Hyperdrive's base token to purchase bonds.
// If false, use the Hyperdrive's `vaultSharesToken`.
bool internal immutable _asBase;

// Positions //

// TODO: Reassess using a more tailored data structure.
/// @dev Utility data structure to manage the position queue.
/// Supports pushing and popping from both the front and back.
DoubleEndedQueue.Bytes32Deque internal _positions;

// ╭─────────────────────────────────────────────────────────╮
// │ Constructor │
// ╰─────────────────────────────────────────────────────────╯

/// @notice Initial configuration paramters for Everlong.
/// @param _name Name of the ERC20 token managed by Everlong.
/// @param _symbol Symbol of the ERC20 token managed by Everlong.
/// @param _hyperdrive Address of the Hyperdrive instance wrapped by Everlong.
/// @param __asBase Whether to use Hyperdrive's base token for bond purchases.
constructor(
string memory _name,
string memory _symbol,
address _hyperdrive,
bool __asBase
)
EverlongERC4626(
_name,
_symbol,
__asBase
? IHyperdrive(_hyperdrive).baseToken()
: IHyperdrive(_hyperdrive).vaultSharesToken()
)
{
// Store constructor parameters.
hyperdrive = _hyperdrive;
_asBase = __asBase;
_admin = msg.sender;

// Give 1 wei approval to make the slot "dirty".
IERC20(_asset).approve(_hyperdrive, 1);
}

// ╭─────────────────────────────────────────────────────────╮
// │ Getters │
// ╰─────────────────────────────────────────────────────────╯

/// @notice Returns the kind of the Everlong instance.
/// @return Everlong contract kind.
function kind() public view virtual returns (string memory) {
return EVERLONG_KIND;
}

/// @notice Returns the version of the Everlong instance.
/// @return Everlong contract version.
function version() public view virtual returns (string memory) {
return EVERLONG_VERSION;
}
/// @dev Close positions until sufficient idle liquidity is held.
/// @dev Reverts if the target is unreachable.
/// @param _target Target amount of idle liquidity to reach.
/// @return idle Amount of idle after the increase.
function _increaseIdle(
uint256 _target
) internal virtual returns (uint256 idle);
}
Loading
Loading