Skip to content

Commit 599067b

Browse files
Very simple deposit/withdraw logic and share accounting (#3)
* Very simple deposit/withdraw logic and share accounting * reformat second-level comments * redeem override + comment updates + contribution guide * update contract version to 0.8.22 and relax lib/interface/test versions * remove redundant comment * cleanup Everlong unit test * fix Everlong test comment * maxDeposit functionality/tests and comment cleanup * remove unused test helper * addressing feedback: remove unnecessary approval + deposit override * addressing feedback: `redeem()` commenting * addressing feedback: _beforeWithdraw virtual assets commenting + todo * addressing feedback: kind/version tests * Update test/units/EverlongERC4626.t.sol Co-authored-by: Alex Towle <[email protected]> * addressing feedback: refactor contracts to more "flat" structure (currently encountering issue with linearization of inheritance) * addressing feedback: remove IEverlong from Everlong inheritance * addressing feedback: remove duplicated test + clean up inheritance * _rebalance() visibility * addressing feedback: immutable decimals + fix `_increaseIdle` logic + set admin in constructor * variable reordering * file casing import fix * Update contracts/internal/EverlongPositions.sol Co-authored-by: Alex Towle <[email protected]> * Update contracts/internal/EverlongPositions.sol Co-authored-by: Alex Towle <[email protected]> * Update contracts/internal/EverlongPositions.sol Co-authored-by: Alex Towle <[email protected]> * Update test/exposed/EverlongExposed.sol Co-authored-by: Alex Towle <[email protected]> * Update test/exposed/EverlongERC4626Exposed.sol Co-authored-by: Alex Towle <[email protected]> * addressing feedback: asBase public function --------- Co-authored-by: Alex Towle <[email protected]>
1 parent d310379 commit 599067b

26 files changed

+762
-377
lines changed

โ€Ž.solhint.json

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"rules": {
44
"func-name-mixedcase": "off",
55
"var-name-mixedcase": "off",
6+
"immutable-vars-naming": "off",
67
"no-unused-vars": "error"
78
}
89
}

โ€ŽCONTRIBUTING.md

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Contributing to Everlong
2+
3+
## Bugfixes & issues
4+
5+
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.
6+
7+
## Release steps
8+
9+
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.
10+
2. [ ] Tag the release with `git tag vX.Y.Z`.
11+
3. [ ] Push the release to Github with `git push --tags`
12+
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.

โ€Žcontracts/Everlong.sol

+62-10
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
// SPDX-License-Identifier: Apache-2.0
2-
pragma solidity 0.8.20;
2+
pragma solidity 0.8.22;
33

4+
import { IHyperdrive } from "hyperdrive/contracts/src/interfaces/IHyperdrive.sol";
5+
import { IEverlong } from "./interfaces/IEverlong.sol";
46
import { EverlongAdmin } from "./internal/EverlongAdmin.sol";
57
import { EverlongBase } from "./internal/EverlongBase.sol";
8+
import { EverlongERC4626 } from "./internal/EverlongERC4626.sol";
69
import { EverlongPositions } from "./internal/EverlongPositions.sol";
10+
import { EVERLONG_KIND, EVERLONG_VERSION } from "./libraries/Constants.sol";
711

812
/// ,---..-. .-.,---. ,---. ,-. .---. .-. .-. ,--,
913
/// | .-' \ \ / / | .-' | .-.\ | | / .-. ) | \| |.' .'
@@ -62,16 +66,64 @@ import { EverlongPositions } from "./internal/EverlongPositions.sol";
6266
/// @custom:disclaimer The language used in this code is for coding convenience
6367
/// only, and is not intended to, and does not, have any
6468
/// particular legal or regulatory significance.
65-
contract Everlong is EverlongAdmin, EverlongPositions {
66-
/// @notice Initial configuration paramters for Everlong.
67-
/// @param _name Name of the ERC20 token managed by Everlong.
68-
/// @param _symbol Symbol of the ERC20 token managed by Everlong.
69-
/// @param __hyperdrive Address of the Hyperdrive instance wrapped by Everlong.
70-
/// @param __asBase Whether to use Hyperdrive's base token for bond purchases.
69+
contract Everlong is EverlongAdmin, EverlongPositions, EverlongERC4626 {
70+
// โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
71+
// โ”‚ Constructor โ”‚
72+
// โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
73+
74+
/// @notice Initial configuration paramters for EverlongERC4626.
75+
/// @param __name Name of the ERC20 token managed by Everlong.
76+
/// @param __symbol Symbol of the ERC20 token managed by Everlong.
77+
/// @param __hyperdrive Address of the Hyperdrive instance.
78+
/// @param __asBase Whether to use the base or shares token from Hyperdrive.
7179
constructor(
72-
string memory _name,
73-
string memory _symbol,
80+
string memory __name,
81+
string memory __symbol,
7482
address __hyperdrive,
7583
bool __asBase
76-
) EverlongBase(_name, _symbol, __hyperdrive, __asBase) {}
84+
) {
85+
// Store constructor parameters.
86+
_name = __name;
87+
_symbol = __symbol;
88+
_hyperdrive = __hyperdrive;
89+
_asBase = __asBase;
90+
_asset = __asBase
91+
? IHyperdrive(__hyperdrive).baseToken()
92+
: IHyperdrive(__hyperdrive).vaultSharesToken();
93+
94+
// Set the admin to the contract deployer.
95+
_admin = msg.sender;
96+
97+
// Attempt to retrieve the decimals from the {_asset} contract.
98+
// If it does not implement `decimals() (uint256)`, use the default.
99+
(bool success, uint8 result) = _tryGetAssetDecimals(_asset);
100+
_decimals = success ? result : _DEFAULT_UNDERLYING_DECIMALS;
101+
}
102+
103+
// โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
104+
// โ”‚ Getters โ”‚
105+
// โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
106+
107+
/// @notice Gets the Everlong instance's kind.
108+
/// @return The Everlong instance's kind.
109+
function kind() external view returns (string memory) {
110+
return EVERLONG_KIND;
111+
}
112+
113+
/// @notice Gets the Everlong instance's version.
114+
/// @return The Everlong instance's version.
115+
function version() external view returns (string memory) {
116+
return EVERLONG_VERSION;
117+
}
118+
119+
/// @notice Gets the address of the underlying Hyperdrive Instance.
120+
function hyperdrive() external view returns (address) {
121+
return _hyperdrive;
122+
}
123+
124+
/// @notice Gets whether Everlong uses Hyperdrive's base token to
125+
/// transact.
126+
function asBase() external view returns (bool) {
127+
return _asBase;
128+
}
77129
}

โ€Žcontracts/interfaces/IEverlong.sol

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: Apache-2.0
2-
pragma solidity 0.8.20;
2+
pragma solidity ^0.8.20;
33

44
import { IERC4626 } from "openzeppelin/interfaces/IERC4626.sol";
55
import { IEverlongAdmin } from "./IEverlongAdmin.sol";
@@ -31,12 +31,12 @@ interface IEverlong is
3131
// โ”‚ Errors โ”‚
3232
// โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
3333

34-
// Admin //
34+
// โ”€โ”€ Admin โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
3535

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

39-
// Positions //
39+
// โ”€โ”€ Positions โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
4040

4141
/// @notice Thrown when attempting to insert a position with
4242
/// a `maturityTime` sooner than the most recent position's.
@@ -45,4 +45,8 @@ interface IEverlong is
4545
/// @notice Thrown when attempting to close a position with
4646
/// a `bondAmount` greater than that contained by the position.
4747
error InconsistentPositionBondAmount();
48+
49+
/// @notice Thrown when a target idle amount is too high to be reached
50+
/// even after closing all positions.
51+
error TargetIdleTooHigh();
4852
}

โ€Žcontracts/interfaces/IEverlongAdmin.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: Apache-2.0
2-
pragma solidity 0.8.20;
2+
pragma solidity ^0.8.20;
33

44
interface IEverlongAdmin {
55
// โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ

โ€Žcontracts/interfaces/IEverlongEvents.sol

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// SPDX-License-Identifier: Apache-2.0
2-
pragma solidity 0.8.20;
2+
pragma solidity ^0.8.20;
33

44
interface IEverlongEvents {
5-
// Admin //
5+
// โ”€โ”€ Admin โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
66

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

10-
// Positions //
10+
// โ”€โ”€ Positions โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
1111

1212
/// @notice Emitted when a new position is added to the bond portfolio.
1313
/// @dev This event will only be emitted with new `maturityTime`s in the portfolio.

โ€Žcontracts/interfaces/IEverlongPositions.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: Apache-2.0
2-
pragma solidity 0.8.20;
2+
pragma solidity ^0.8.20;
33

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

โ€Žcontracts/internal/EverlongAdmin.sol

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// SPDX-License-Identifier: Apache-2.0
2-
pragma solidity 0.8.20;
2+
pragma solidity 0.8.22;
33

44
import { IEverlong } from "../interfaces/IEverlong.sol";
55
import { IEverlongAdmin } from "../interfaces/IEverlongAdmin.sol";
6-
import { EverlongBase } from "./EverlongBase.sol";
6+
import { EverlongBase } from "../internal/EverlongBase.sol";
77

88
/// @author DELV
99
/// @title EverlongAdmin
+13-74
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
// SPDX-License-Identifier: Apache-2.0
2-
pragma solidity 0.8.20;
2+
pragma solidity 0.8.22;
33

4-
import { IHyperdrive } from "hyperdrive/contracts/src/interfaces/IHyperdrive.sol";
54
import { DoubleEndedQueue } from "openzeppelin/utils/structs/DoubleEndedQueue.sol";
6-
import { IERC20 } from "openzeppelin/interfaces/IERC20.sol";
75
import { IEverlongEvents } from "../interfaces/IEverlongEvents.sol";
8-
import { EVERLONG_KIND, EVERLONG_VERSION } from "../libraries/Constants.sol";
9-
import { EverlongERC4626 } from "./EverlongERC4626.sol";
6+
import { EverlongStorage } from "./EverlongStorage.sol";
107

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

2219
// โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
23-
// โ”‚ Storage โ”‚
20+
// โ”‚ Stateful โ”‚
2421
// โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
2522

26-
// Admin //
23+
/// @dev Rebalances the Everlong bond portfolio if needed.
24+
function _rebalance() internal virtual;
2725

28-
/// @dev Address of the contract admin.
29-
address internal _admin;
30-
31-
// Hyperdrive //
32-
33-
/// @dev Address of the Hyperdrive instance wrapped by Everlong.
34-
address public immutable hyperdrive;
35-
36-
/// @dev Whether to use Hyperdrive's base token to purchase bonds.
37-
// If false, use the Hyperdrive's `vaultSharesToken`.
38-
bool internal immutable _asBase;
39-
40-
// Positions //
41-
42-
// TODO: Reassess using a more tailored data structure.
43-
/// @dev Utility data structure to manage the position queue.
44-
/// Supports pushing and popping from both the front and back.
45-
DoubleEndedQueue.Bytes32Deque internal _positions;
46-
47-
// โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
48-
// โ”‚ Constructor โ”‚
49-
// โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
50-
51-
/// @notice Initial configuration paramters for Everlong.
52-
/// @param _name Name of the ERC20 token managed by Everlong.
53-
/// @param _symbol Symbol of the ERC20 token managed by Everlong.
54-
/// @param _hyperdrive Address of the Hyperdrive instance wrapped by Everlong.
55-
/// @param __asBase Whether to use Hyperdrive's base token for bond purchases.
56-
constructor(
57-
string memory _name,
58-
string memory _symbol,
59-
address _hyperdrive,
60-
bool __asBase
61-
)
62-
EverlongERC4626(
63-
_name,
64-
_symbol,
65-
__asBase
66-
? IHyperdrive(_hyperdrive).baseToken()
67-
: IHyperdrive(_hyperdrive).vaultSharesToken()
68-
)
69-
{
70-
// Store constructor parameters.
71-
hyperdrive = _hyperdrive;
72-
_asBase = __asBase;
73-
_admin = msg.sender;
74-
75-
// Give 1 wei approval to make the slot "dirty".
76-
IERC20(_asset).approve(_hyperdrive, 1);
77-
}
78-
79-
// โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
80-
// โ”‚ Getters โ”‚
81-
// โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
82-
83-
/// @notice Returns the kind of the Everlong instance.
84-
/// @return Everlong contract kind.
85-
function kind() public view virtual returns (string memory) {
86-
return EVERLONG_KIND;
87-
}
88-
89-
/// @notice Returns the version of the Everlong instance.
90-
/// @return Everlong contract version.
91-
function version() public view virtual returns (string memory) {
92-
return EVERLONG_VERSION;
93-
}
26+
/// @dev Close positions until sufficient idle liquidity is held.
27+
/// @dev Reverts if the target is unreachable.
28+
/// @param _target Target amount of idle liquidity to reach.
29+
/// @return idle Amount of idle after the increase.
30+
function _increaseIdle(
31+
uint256 _target
32+
) internal virtual returns (uint256 idle);
9433
}

0 commit comments

Comments
ย (0)