Skip to content
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
577 changes: 577 additions & 0 deletions broadcast/DeploySorellaVaultSimple.s.sol/1/run-1750205587.json

Large diffs are not rendered by default.

577 changes: 577 additions & 0 deletions broadcast/DeploySorellaVaultSimple.s.sol/1/run-latest.json

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,21 @@ bartio = "${BARTIO_RPC_URL}"
holesky = "${HOLESKY_RPC_URL}"

[etherscan]
corn = { key = "${CORNSCAN_KEY}", chain = 21000000, url = "https://api.routescan.io/v2/network/mainnet/evm/21000000/etherscan" }
arbitrum = { key = "${ARBISCAN_KEY}" }
# corn = { key = "${CORNSCAN_KEY}", chain = 21000000, url = "https://api.routescan.io/v2/network/mainnet/evm/21000000/etherscan" }
# arbitrum = { key = "${ARBISCAN_KEY}" }
mainnet = { key = "${ETHERSCAN_KEY}" }
polygon = { key = "${POLYGONSCAN_KEY}" }
bsc = { key = "${BSCSCAN_KEY}" }
avalanche = { key = "${SNOWTRACE_KEY}" }
optimism = { key = "${OPTIMISMSCAN_KEY}" }
base = { key = "${BASESCAN_KEY}" }
scroll = { key = "${SCROLLSCAN_KEY}" }
sonicMainnet = { key = "${SONICSCAN_KEY}", chain = 146, url = "https://api.routescan.io/v2/network/mainnet/evm/146/etherscan" }
swell = { key = "${SWELLSCAN_KEY}", chain = 1923, url = "https://explorer.swellnetwork.io:443/api/" }
berachainTestnet = { key = "${BERASCAN_TESTNET_KEY}", chain = 80000, url = "https://api.routescan.io/v2/network/testnet/evm/80000/etherscan" }
sepolia = { key = "${ETHERSCAN_KEY}" }
berachain = { key = "verifyContract", chain = 80094, url = "https://api.routescan.io/v2/network/mainnet/evm/80094/etherscan" }
bob = { key = "${BOBSCAN_KEY}", chain = 60808, url = "https://explorer.gobob.xyz/api?" }
# polygon = { key = "${POLYGONSCAN_KEY}" }
# bsc = { key = "${BSCSCAN_KEY}" }
# avalanche = { key = "${SNOWTRACE_KEY}" }
# optimism = { key = "${OPTIMISMSCAN_KEY}" }
# base = { key = "${BASESCAN_KEY}" }
# scroll = { key = "${SCROLLSCAN_KEY}" }
# sonicMainnet = { key = "${SONICSCAN_KEY}", chain = 146, url = "https://api.routescan.io/v2/network/mainnet/evm/146/etherscan" }
# swell = { key = "${SWELLSCAN_KEY}", chain = 1923, url = "https://explorer.swellnetwork.io:443/api/" }
# berachainTestnet = { key = "${BERASCAN_TESTNET_KEY}", chain = 80000, url = "https://api.routescan.io/v2/network/testnet/evm/80000/etherscan" }
# sepolia = { key = "${ETHERSCAN_KEY}" }
# berachain = { key = "verifyContract", chain = 80094, url = "https://api.routescan.io/v2/network/mainnet/evm/80094/etherscan" }
# bob = { key = "${BOBSCAN_KEY}", chain = 60808, url = "https://explorer.gobob.xyz/api?" }

[fmt]
FOUNDRY_FMT_LINE_LENGTH = 120
Expand Down
108 changes: 108 additions & 0 deletions script/DeploySorellaVaultSimple.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

import {Auth, Authority} from "@solmate/src/auth/Auth.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {UniswapV4FluxManager, FluxManager} from "src/managers/UniswapV4FluxManager.sol";
import {IntentsTeller} from "src/tellers/IntentsTeller.sol";
import {BoringVault} from "src/BoringVault.sol";
import {ERC20} from "@solmate/src/tokens/ERC20.sol";
import {RolesAuthority, Authority} from "@solmate/src/auth/authorities/RolesAuthority.sol";
import {ChainlinkDatum} from "src/datums/ChainlinkDatum.sol";
import {Script} from "@forge-std/Script.sol";
import {PoolId, IPoolManager} from "lib/v4-core/src/libraries/StateLibrary.sol";

contract DeploySorellaVaultSimple is Script {
RolesAuthority internal rolesAuthority;
BoringVault internal boringVault;
ChainlinkDatum internal datum;
UniswapV4FluxManager internal manager;
address internal positionManager = 0xbD216513d74C8cf14cf4747E6AaA6420FF64ee9e;
address internal universalRouter = 0x66a9893cC07D91D95644AEDD05D03f95e1dBA8Af;
ERC20 internal token0 = ERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
ERC20 internal token1 = ERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
address internal nativeWrapper = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
IPoolManager internal poolManager = IPoolManager(0x000000000004444c5dc75cB358380D2e3dE08A90);
PoolId internal eth_usdc_pool_id = PoolId.wrap(0xF4CEA555F4656F4561ECD2A74EC2673331779220CD60686514983EDB16D027F3);
address internal ETH_USD_ORACLE = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419;
address internal hook = 0x0000000AA8c2Fb9b232F78D2B286dC2aE53BfAD4; // angstrom
bool internal baseIn0Or1 = false;

address internal scriptOwner;
address internal owner;
address internal payout;
address internal strategist;
Comment on lines +31 to +34
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: These state variables (owner, payout, strategist) are declared but never initialized, which will cause role assignment to fail on line 95


uint24 internal poolFee = uint24(0x800000);
int24 internal tickSpacing = int24(10);

function run() public {
vm.startBroadcast();
/// DEPLOY CONTRACTS

// ownership for test deployment set to scriptOwner
scriptOwner = msg.sender;

// deploy roles authority with scriptOwner as owner
rolesAuthority = new RolesAuthority(scriptOwner, Authority(address(0)));

// deploy boring vault with scriptOwner as owner
boringVault = new BoringVault(scriptOwner, "Test0", "T0", 18);

// deploy datum
datum = new ChainlinkDatum(ETH_USD_ORACLE, 1 days, true);

// deploy manager with scriptOwner as owner
manager = new UniswapV4FluxManager(
UniswapV4FluxManager.ConstructorArgs({
owner: address(scriptOwner),
boringVault: address(boringVault),
token0: address(token0),
token1: address(token1),
baseIn0Or1: baseIn0Or1,
nativeWrapper: nativeWrapper,
datum: address(datum),
datumLowerBound: 0.995e4,
datumUpperBound: 1.005e4,
positionManager: positionManager,
universalRouter: universalRouter,
hook: hook,
poolFee: poolFee,
tickSpacing: tickSpacing
})
);

// set roles authority as authority for boring vault
boringVault.setAuthority(rolesAuthority);

// set roles authority as authority for manager
manager.setAuthority(rolesAuthority);

// create role capability for managing the vault
rolesAuthority.setRoleCapability(
1, address(boringVault), bytes4(keccak256(abi.encodePacked("manage(address,bytes,uint256)"))), true
);

// grant the manager the role to manage the vault
rolesAuthority.setUserRole(address(manager), 1, true);

// create a role for calling rebalance on the manager
rolesAuthority.setRoleCapability(
7, address(manager), bytes4(keccak256(abi.encodePacked("rebalance(uint256,(uint8,bytes)[])"))), true
);

// grant the strategist address the role to rebalance
rolesAuthority.setUserRole(strategist, 7, true);

// set payout address
manager.setPayout(strategist);

// set performance fee
manager.setPerformanceFee(0.2e4);

// TODO: deploy and grant roles to the teller, complete all other prod roles
// TODO: ownership xfer

vm.stopBroadcast();
}
}
48 changes: 13 additions & 35 deletions src/managers/FluxManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,8 @@ abstract contract FluxManager is Auth {
uint16 public datumUpperBound;

uint16 public performanceFee;
uint64 public lastPerformanceReview;
uint64 public performanceReviewFrequency;
address public payout;
uint128 public pendingFee;
uint128 totalSupplyLastReview;

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERRORS */
Expand Down Expand Up @@ -80,14 +77,15 @@ abstract contract FluxManager is Auth {
/* IMMUTABLES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

BoringVault internal immutable boringVault;
BoringVault public immutable boringVault;
ERC20 public immutable token0;
ERC20 public immutable token1;
uint8 internal immutable decimals0;
uint8 internal immutable decimals1;
uint8 internal immutable decimalsBoring;
bool internal immutable baseIn0Or1; // Only used for initial share price when zero shares outstanding, and for totalAssets check
address internal immutable nativeWrapper;
bool public immutable baseIn0Or1; // Only used for initial share price when zero shares outstanding, and for totalAssets check
bool public immutable token0IsNative;
address public immutable nativeWrapper;

constructor(
address _owner,
Expand All @@ -107,6 +105,7 @@ abstract contract FluxManager is Auth {
decimals1 = token1.decimals();
decimalsBoring = boringVault.decimals();
baseIn0Or1 = _baseIn0Or1;
token0IsNative = _token0 == address(0);
nativeWrapper = _nativeWrapper;
datum = IDatum(_datum);

Expand Down Expand Up @@ -136,8 +135,8 @@ abstract contract FluxManager is Auth {
emit Unpaused();
}

function claimFees(bool token0Or1) external requiresAuth {
_claimFees(token0Or1);
function claimFees() external requiresAuth {
_claimFees();
}

function setPayout(address newPayout) external requiresAuth {
Expand All @@ -162,14 +161,6 @@ abstract contract FluxManager is Auth {
emit DatumConfigured();
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FLUX ACCOUNTING */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

function refreshInternalFluxAccounting() external requiresAuth {
_refreshInternalFluxAccounting();
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FLUX VIEW */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
Expand All @@ -184,15 +175,11 @@ abstract contract FluxManager is Auth {
(uint256 token0Assets, uint256 token1Assets) = _totalAssets(exchangeRate);
if (quoteIn0Or1) {
// Return totalAssets in token0
uint256 converted = token1Assets * (10 ** decimals0);
converted = converted.mulDivDown(10 ** decimals1, exchangeRate);
converted /= 10 ** decimals1;
uint256 converted = token1Assets.mulDivDown(10 ** decimals0, exchangeRate);
assets = token0Assets + converted;
} else {
// Return totalAssets in token1
uint256 converted = token0Assets * (10 ** decimals1);
converted = converted.mulDivDown(exchangeRate, 10 ** decimals1);
converted /= 10 ** decimals0;
uint256 converted = token0Assets.mulDivDown(exchangeRate, 10 ** decimals0);
assets = token1Assets + converted;
}
}
Expand All @@ -214,7 +201,7 @@ abstract contract FluxManager is Auth {
} else if (!baseIn0Or1 && quoteIn0Or1) {
return uint256(10 ** decimals0).mulDivDown(10 ** decimals1, exchangeRate);
} else if (baseIn0Or1 && !quoteIn0Or1) {
return uint256(10 ** decimals1).mulDivDown(exchangeRate, 10 ** decimals1);
return exchangeRate;
} else if (!baseIn0Or1 && !quoteIn0Or1) {
return 10 ** decimals1;
} else {
Expand All @@ -236,28 +223,19 @@ abstract contract FluxManager is Auth {
/* FLUX INTERNAL */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

function _claimFees(bool token0Or1) internal {
function _claimFees() internal {
uint256 pending = pendingFee;
if (pending > 0) {
address token = token0Or1 ? address(token0) : address(token1);
address token = baseIn0Or1 ? (token0IsNative ? address(nativeWrapper) : address(token0)) : address(token1);
pendingFee = 0;
if (address(token) == address(0)) {
// Transfer it.
boringVault.manage(nativeWrapper, abi.encodeWithSelector(ERC20.transfer.selector, payout, pending), 0);
} else {
// Transfer it.
boringVault.manage(token, abi.encodeWithSelector(ERC20.transfer.selector, payout, pending), 0);
}
boringVault.manage(token, abi.encodeWithSelector(ERC20.transfer.selector, payout, pending), 0);
}
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ABSTRACT FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/// @notice Refresh internal flux constants(like ERC20 token balances)
function _refreshInternalFluxAccounting() internal virtual;

function _totalAssets(uint256 exchangeRate)
internal
view
Expand Down
Loading
Loading