Skip to content
Open
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
9 changes: 2 additions & 7 deletions script/CreateAndStake.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,8 @@ contract CreateAndStake is Script {
// Address of the EthMultiVault contract
address payable public constant ETH_MULTI_VAULT = payable(0x63B90A9c109fF8f137916026876171ffeEdEe714);

bytes[] public ATOM_URIS = [
bytes("intuition.systems"),
bytes("is"),
bytes("bullish"),
bytes("cat"),
bytes("internet")
];
bytes[] public ATOM_URIS =
[bytes("intuition.systems"), bytes("is"), bytes("bullish"), bytes("cat"), bytes("internet")];

uint256[] public ATOM_IDS;

Expand Down
69 changes: 21 additions & 48 deletions src/BondingCurveRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;

import {Ownable, Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";

import {IBaseCurve} from "src/interfaces/IBaseCurve.sol";
import {IBondingCurveRegistry} from "src/interfaces/IBondingCurveRegistry.sol";
import {Errors} from "src/libraries/Errors.sol";
Expand All @@ -20,73 +22,55 @@ import {Errors} from "src/libraries/Errors.sol";
* You can think of the registry as a concierge the EthMultiVault uses to access various
* economic incentive patterns.
*/
contract BondingCurveRegistry is IBondingCurveRegistry {
contract BondingCurveRegistry is IBondingCurveRegistry, Ownable2Step {
/* =================================================== */
/* STATE VARIABLES */
/* =================================================== */

// Quantity of known curves, used to assign IDs
/// @notice Quantity of known curves, used to assign IDs
uint256 public count;

// Mapping of curve IDs to curve addresses, used for lookup
/// @notice Mapping of curve IDs to curve addresses, used for lookup
mapping(uint256 => address) public curveAddresses;

// Mapping of curve addresses to curve IDs, for reverse lookup
/// @notice Mapping of curve addresses to curve IDs, for reverse lookup
mapping(address => uint256) public curveIds;

// Mapping of the registered curve names, used to enforce uniqueness
/// @notice Mapping of the registered curve names, used to enforce uniqueness
mapping(string => bool) public registeredCurveNames;

// Address of the admin who may add curves to the registry
address public admin;

/* =================================================== */
/* EVENTS */
/* =================================================== */

/// @notice Emitted when a new curve is added to the registry
///
/// @param curveId The ID of the curve
/// @param curveAddress The address of the curve
/// @param curveName The name of the curve
event BondingCurveAdded(uint256 indexed curveId, address indexed curveAddress, string indexed curveName);

/// @notice Emitted when the admin role is transferred
/// @param oldAdmin The previous admin address
/// @param newAdmin The new admin address
event OwnershipTransferred(address indexed oldAdmin, address indexed newAdmin);

/* =================================================== */
/* CONSTRUCTOR */
/* =================================================== */

/// @notice Constructor for the BondingCurveRegistry contract
/// @param _admin Address who may add curves to the registry
constructor(address _admin) {
if (_admin == address(0)) {
revert Errors.BondingCurveRegistry_RequiresOwner();
}
admin = _admin;
emit OwnershipTransferred(address(0), _admin);
}
constructor(address _admin) Ownable(_admin) {}

/* =================================================== */
/* RESTRICTED FUNCTIONS */
/* ACCESS-RESTRICTED FUNCTIONS */
/* =================================================== */

/// @notice Add a new bonding curve to the registry
/// @param bondingCurve Address of the new bonding curve
function addBondingCurve(address bondingCurve) external {
if (msg.sender != admin) {
revert Errors.BondingCurveRegistry_OnlyOwner();
function addBondingCurve(address bondingCurve) external onlyOwner {
if (bondingCurve == address(0)) {
revert Errors.BondingCurveRegistry_ZeroAddress();
}

// Ensure curve is not already registered
if (curveIds[bondingCurve] != 0) {
revert Errors.BondingCurveRegistry_CurveAlreadyExists();
}

// Enforce curve name uniqueness
string memory curveName = IBaseCurve(bondingCurve).name();

// Ensure the curve name is not empty
if (bytes(curveName).length == 0) {
revert Errors.BondingCurveRegistry_EmptyCurveName();
}

// Enforce curve name uniqueness
if (registeredCurveNames[curveName]) {
revert Errors.BondingCurveRegistry_CurveNameNotUnique();
}
Expand All @@ -104,19 +88,8 @@ contract BondingCurveRegistry is IBondingCurveRegistry {
emit BondingCurveAdded(count, bondingCurve, curveName);
}

/// @notice Transfer the admin role to a new address
/// @param newOwner The new admin address
function transferOwnership(address newOwner) external {
if (msg.sender != admin) {
revert Errors.BondingCurveRegistry_OnlyOwner();
}
address oldAdmin = admin;
admin = newOwner;
emit OwnershipTransferred(oldAdmin, newOwner);
}

/* =================================================== */
/* PUBLIC FUNCTIONS */
/* VIEW FUNCTIONS */
/* =================================================== */

/// @notice Preview how many shares would be minted for a deposit of assets
Expand Down
21 changes: 15 additions & 6 deletions src/EthMultiVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -500,10 +500,7 @@ contract EthMultiVault is IEthMultiVault, Initializable, ReentrancyGuardUpgradea
address oldRegistry = bondingCurveConfig.registry;
uint256 oldDefaultCurveId = bondingCurveConfig.defaultCurveId;

bondingCurveConfig = BondingCurveConfig({
registry: newRegistry,
defaultCurveId: _defaultCurveId
});
bondingCurveConfig = BondingCurveConfig({registry: newRegistry, defaultCurveId: _defaultCurveId});

emit BondingCurveConfigSet(newRegistry, _defaultCurveId, oldRegistry, oldDefaultCurveId);
}
Expand Down Expand Up @@ -1801,7 +1798,13 @@ contract EthMultiVault is IEthMultiVault, Initializable, ReentrancyGuardUpgradea
bondingCurveVaults[id][curveId].totalAssets += assetsDelta;
bondingCurveVaults[id][curveId].totalShares += sharesDelta;
uint256 newSharePrice = currentSharePriceCurve(id, curveId);
emit SharePriceChangedCurve(id, curveId, newSharePrice, bondingCurveVaults[id][curveId].totalAssets, bondingCurveVaults[id][curveId].totalShares);
emit SharePriceChangedCurve(
id,
curveId,
newSharePrice,
bondingCurveVaults[id][curveId].totalAssets,
bondingCurveVaults[id][curveId].totalShares
);
}

/// @dev decrease the total assets and shares for a given bonding curve vault
Expand All @@ -1818,7 +1821,13 @@ contract EthMultiVault is IEthMultiVault, Initializable, ReentrancyGuardUpgradea
bondingCurveVaults[id][curveId].totalAssets -= assetsDelta;
bondingCurveVaults[id][curveId].totalShares -= sharesDelta;
uint256 newSharePrice = currentSharePriceCurve(id, curveId);
emit SharePriceChangedCurve(id, curveId, newSharePrice, bondingCurveVaults[id][curveId].totalAssets, bondingCurveVaults[id][curveId].totalShares);
emit SharePriceChangedCurve(
id,
curveId,
newSharePrice,
bondingCurveVaults[id][curveId].totalAssets,
bondingCurveVaults[id][curveId].totalShares
);
}

/// @dev internal method for vault creation
Expand Down
15 changes: 15 additions & 0 deletions src/interfaces/IBondingCurveRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ pragma solidity ^0.8.27;
* @notice Interface for the BondingCurveRegistry contract. Routes access to the curves associated with atoms & triples.
*/
interface IBondingCurveRegistry {
/* =================================================== */
/* EVENTS */
/* =================================================== */

/// @notice Emitted when a new curve is added to the registry
///
/// @param curveId The ID of the curve
/// @param curveAddress The address of the curve
/// @param curveName The name of the curve
event BondingCurveAdded(uint256 indexed curveId, address indexed curveAddress, string indexed curveName);

/* =================================================== */
/* FUNCTIONS */
/* =================================================== */

/// @notice Preview how many shares would be minted for a deposit of assets
/// @param assets Quantity of assets to deposit
/// @param totalAssets Total quantity of assets already staked into the curve
Expand Down
24 changes: 13 additions & 11 deletions src/interfaces/IEthMultiVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {IPermit2} from "src/interfaces/IPermit2.sol";
/// @author 0xIntuition
/// @notice Interface for managing many ERC4626 style vaults in a single contract
interface IEthMultiVault {

/* =================================================== */
/* CONFIGS STRUCTS */
/* =================================================== */
Expand Down Expand Up @@ -111,10 +110,11 @@ interface IEthMultiVault {
/* =================================================== */

enum ApprovalTypes {
NONE, // 0b00
DEPOSIT, // 0b01
REDEMPTION, // 0b10
BOTH // 0b11
NONE, // 0b00
DEPOSIT, // 0b01
REDEMPTION, // 0b10
BOTH // 0b11

}

/* =================================================== */
Expand Down Expand Up @@ -301,7 +301,9 @@ interface IEthMultiVault {
///
/// @param newAtomDepositFractionForTriple new atom deposit fraction for triples
/// @param oldAtomDepositFractionForTriple old atom deposit fraction for triples
event AtomDepositFractionForTripleSet(uint256 newAtomDepositFractionForTriple, uint256 oldAtomDepositFractionForTriple);
event AtomDepositFractionForTripleSet(
uint256 newAtomDepositFractionForTriple, uint256 oldAtomDepositFractionForTriple
);

/// @notice emitted upon changing the bonding curve configuration
///
Expand All @@ -310,10 +312,7 @@ interface IEthMultiVault {
/// @param oldRegistry address of the old bonding curve registry
/// @param oldDefaultCurveId old default curve ID
event BondingCurveConfigSet(
address indexed newRegistry,
uint256 newDefaultCurveId,
address indexed oldRegistry,
uint256 oldDefaultCurveId
address indexed newRegistry, uint256 newDefaultCurveId, address indexed oldRegistry, uint256 oldDefaultCurveId
);

/// @notice emitted upon changing the entry fee
Expand Down Expand Up @@ -901,7 +900,10 @@ interface IEthMultiVault {
/// @param receiver address of the receiver
///
/// @return shares number of shares user has in the vault
function getVaultStateForUserCurve(uint256 vaultId, uint256 curveId, address receiver) external view returns (uint256, uint256);
function getVaultStateForUserCurve(uint256 vaultId, uint256 curveId, address receiver)
external
view
returns (uint256, uint256);

/// @notice returns the shares for recipient and other important values when depositing 'assets' into a bonding curve vault
///
Expand Down
5 changes: 3 additions & 2 deletions src/libraries/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ library Errors {
error EthMultiVault_VaultNotAtom();
error EthMultiVault_VaultNotTriple();
error EthMultiVault_InvalidRegistry();

///////// ATOMWALLET ERRORS /////////////////////////////////////////////////////////////

error AtomWallet_InvalidCallDataLength();
Expand Down Expand Up @@ -76,8 +77,8 @@ library Errors {

error BondingCurveRegistry_CurveAlreadyExists();
error BondingCurveRegistry_CurveNameNotUnique();
error BondingCurveRegistry_OnlyOwner();
error BondingCurveRegistry_RequiresOwner();
error BondingCurveRegistry_EmptyCurveName();
error BondingCurveRegistry_ZeroAddress();

///////// BASE CURVE ERRORS /////////////////////////////////////////////////////////////////////////

Expand Down
1 change: 1 addition & 0 deletions test/EthMultiVaultBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {BondingCurveRegistry} from "src/BondingCurveRegistry.sol";
import {ProgressiveCurve} from "src/ProgressiveCurve.sol";
import {LinearCurve} from "src/LinearCurve.sol";
import {OffsetProgressiveCurve} from "src/OffsetProgressiveCurve.sol";

contract EthMultiVaultBase is Test {
// msg.value - atomCreationProtocolFee - protocolFee

Expand Down
41 changes: 22 additions & 19 deletions test/UpgradeTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ contract UpgradeTest is Test {
progressiveCurve = new ProgressiveCurve("Progressive Curve", 2);

// Deploy the OffsetProgressiveCurve contract
offsetProgressiveCurve = new OffsetProgressiveCurve("Offset Progressive Curve", 2,5e35);
offsetProgressiveCurve = new OffsetProgressiveCurve("Offset Progressive Curve", 2, 5e35);

// Add the LinearCurve to the BondingCurveRegistry
vm.prank(admin);
Expand All @@ -90,16 +90,11 @@ contract UpgradeTest is Test {
address newEthMultiVaultImplementation = address(new EthMultiVault());

// Prepare the bonding curve configuration
IEthMultiVault.BondingCurveConfig memory bondingCurveConfig = IEthMultiVault.BondingCurveConfig({
registry: address(bondingCurveRegistry),
defaultCurveId: 1
});
IEthMultiVault.BondingCurveConfig memory bondingCurveConfig =
IEthMultiVault.BondingCurveConfig({registry: address(bondingCurveRegistry), defaultCurveId: 1});

// Prepare initialization data for the upgrade
bytes memory reinitData = abi.encodeWithSelector(
EthMultiVault.reinitialize.selector,
bondingCurveConfig
);
bytes memory reinitData = abi.encodeWithSelector(EthMultiVault.reinitialize.selector, bondingCurveConfig);

address proxyAdminOwner = proxyAdmin.owner();

Expand Down Expand Up @@ -491,7 +486,8 @@ contract UpgradeTest is Test {

(uint256 sharesForReceiverBefore,) = ethMultiVault.getVaultStateForUserCurve(atomId, progressiveCurveId, alice);

uint256 expectedSharesForReceiver = _getExpectedSharesForReceiverCurve(depositAmountAfterGhostShares, atomId, progressiveCurveId);
uint256 expectedSharesForReceiver =
_getExpectedSharesForReceiverCurve(depositAmountAfterGhostShares, atomId, progressiveCurveId);

uint256 protocolMultisigBalanceBefore = address(_getProtocolMultisig()).balance;

Expand Down Expand Up @@ -529,7 +525,8 @@ contract UpgradeTest is Test {

uint256 userEthBalanceBeforeRedeem = address(alice).balance;

uint256 assetsForReceiverBeforeFees = ethMultiVault.convertToAssetsCurve(redeemAmount, atomId, progressiveCurveId);
uint256 assetsForReceiverBeforeFees =
ethMultiVault.convertToAssetsCurve(redeemAmount, atomId, progressiveCurveId);
uint256 protocolFeeAmount = ethMultiVault.protocolFeeAmount(assetsForReceiverBeforeFees, atomId);

uint256 protocolMultisigBalanceBefore = address(_getProtocolMultisig()).balance;
Expand Down Expand Up @@ -565,17 +562,21 @@ contract UpgradeTest is Test {
uint256 expectedGhostShares = _getGhostSharesAmount();
uint256 depositAmountAfterGhostShares = depositAmount - (expectedGhostShares * 2); // ghost shares are minted for both the positive and counter vaults

(uint256 sharesForReceiverBefore,) = ethMultiVault.getVaultStateForUserCurve(tripleId, progressiveCurveId, alice);
(uint256 sharesForReceiverBefore,) =
ethMultiVault.getVaultStateForUserCurve(tripleId, progressiveCurveId, alice);

uint256 expectedSharesForReceiver = _getExpectedSharesForReceiverCurve(depositAmountAfterGhostShares, tripleId, progressiveCurveId);
uint256 expectedSharesForReceiver =
_getExpectedSharesForReceiverCurve(depositAmountAfterGhostShares, tripleId, progressiveCurveId);

uint256 protocolMultisigBalanceBefore = address(_getProtocolMultisig()).balance;

uint256 mintedShares = ethMultiVault.depositTripleCurve{value: depositAmount}(alice, tripleId, progressiveCurveId);
uint256 mintedShares =
ethMultiVault.depositTripleCurve{value: depositAmount}(alice, tripleId, progressiveCurveId);

uint256 protocolMultisigBalanceAfter = address(_getProtocolMultisig()).balance;

(uint256 ghostSharesForPositiveVault,) = ethMultiVault.getVaultStateForUserCurve(tripleId, progressiveCurveId, _getAdmin());
(uint256 ghostSharesForPositiveVault,) =
ethMultiVault.getVaultStateForUserCurve(tripleId, progressiveCurveId, _getAdmin());
(uint256 ghostSharesForCounterVault,) = ethMultiVault.getVaultStateForUserCurve(
ethMultiVault.getCounterIdFromTriple(tripleId), progressiveCurveId, _getAdmin()
);
Expand Down Expand Up @@ -613,7 +614,8 @@ contract UpgradeTest is Test {

uint256 userEthBalanceBeforeRedeem = address(alice).balance;

uint256 assetsForReceiverBeforeFees = ethMultiVault.convertToAssetsCurve(redeemAmount, tripleId, progressiveCurveId);
uint256 assetsForReceiverBeforeFees =
ethMultiVault.convertToAssetsCurve(redeemAmount, tripleId, progressiveCurveId);
uint256 protocolFeeAmount = ethMultiVault.protocolFeeAmount(assetsForReceiverBeforeFees, tripleId);

uint256 protocolMultisigBalanceBefore = address(_getProtocolMultisig()).balance;
Expand All @@ -640,7 +642,7 @@ contract UpgradeTest is Test {
returns (uint256 expectedSharesForReceiver)
{
uint256 depositAmountAfterProtocolFees = depositAmount - ethMultiVault.protocolFeeAmount(depositAmount, termId);

// Handle atom deposits for triple vaults
uint256 atomDeposits = ethMultiVault.atomDepositsAmount(depositAmountAfterProtocolFees, termId);
uint256 userAssetsAfterAtomDeposits = depositAmountAfterProtocolFees - atomDeposits;
Expand Down Expand Up @@ -700,6 +702,7 @@ contract UpgradeTest is Test {
{
uint256 depositAmountAfterProtocolFees = depositAmount - ethMultiVault.protocolFeeAmount(depositAmount, termId);

(,, expectedSharesForReceiver,) = ethMultiVault.getDepositSharesAndFeesCurve(depositAmountAfterProtocolFees, termId, curveId);
(,, expectedSharesForReceiver,) =
ethMultiVault.getDepositSharesAndFeesCurve(depositAmountAfterProtocolFees, termId, curveId);
}
}
}
Loading
Loading