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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/Solady"]
path = lib/Solady
url = https://github.com/Vectorized/solady
56 changes: 33 additions & 23 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,47 @@ remappings = [
"@openzeppelin/=lib/openzeppelin-contracts/",
"@ccip=lib/ccip/",
"@oapp-auth=lib/OAppAuth/src/",
"@solady/=lib/Solady/src/"
]

[rpc_endpoints]
mainnet = "${MAINNET_RPC_URL}"
polygon = "${MATIC_RPC_URL}"
bsc = "${BNB_RPC_URL}"
avalanche = "${AVALANCHE_RPC_URL}"
# polygon = "${MATIC_RPC_URL}"
# bsc = "${BNB_RPC_URL}"
# avalanche = "${AVALANCHE_RPC_URL}"
arbitrum = "${ARBITRUM_RPC_URL}"
optimism = "${OPTIMISM_RPC_URL}"
base = "${BASE_RPC_URL}"
zircuit = "${ZIRCUIT_RPC_URL}"
scroll = "${SCROLL_RPC_URL}"
linea = "${LINEA_RPC_URL}"
sepolia = "${SEPOLIA_RPC_URL}"
sonicTestnet = "${SONIC_TESTNET_RPC_URL}"
corn = "${CORN_MAIZENET_RPC_URL}"
swell = "${SWELL_CHAIN_RPC_URL}"
# optimism = "${OPTIMISM_RPC_URL}"
# base = "${BASE_RPC_URL}"
# zircuit = "${ZIRCUIT_RPC_URL}"
# scroll = "${SCROLL_RPC_URL}"
# linea = "${LINEA_RPC_URL}"
# sepolia = "${SEPOLIA_RPC_URL}"
# sonicTestnet = "${SONIC_TESTNET_RPC_URL}"
# corn = "${CORN_MAIZENET_RPC_URL}"
# swell = "${SWELL_CHAIN_RPC_URL}"
# berachainTestnet = "${BERA_TESTNET_RPC_URL}"
# berachain = "${BERA_CHAIN_RPC_URL}"
# bartio = "${BARTIO_RPC_URL}"
holesky = "${HOLESKY_RPC_URL}"
sonicMainnet = "${SONIC_MAINNET_RPC_URL}"
# sonicMainnet = "${SONIC_MAINNET_RPC_URL}"
hyperliquid = "${HYPERLIQUID_RPC_URL}"

[etherscan]
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" }
#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" }


[fmt]
FOUNDRY_FMT_LINE_LENGTH = 120
Expand Down
71 changes: 71 additions & 0 deletions leafs/Hyperliquid/hyperBtcCarryAdminLeafs.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/Solady
Submodule Solady added at 9298d0
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;

import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {ERC20} from "@solmate/tokens/ERC20.sol";
import {Strings} from "lib/openzeppelin-contracts/contracts/utils/Strings.sol";
import {ERC4626} from "@solmate/tokens/ERC4626.sol";
import {ManagerWithMerkleVerification} from "src/base/Roles/ManagerWithMerkleVerification.sol";
import {MerkleTreeHelper} from "test/resources/MerkleTreeHelper/MerkleTreeHelper.sol";
import "forge-std/Script.sol";

contract CreateBtcCarryMerkleRootScript is Script, MerkleTreeHelper {
using FixedPointMathLib for uint256;

// Updated common addresses for Hyperliquid testnet
address public boringVault = 0x1111111111111111111111111111111111111111;
address public managerAddress = 0x2222222222222222222222222222222222222222;
address public accountantAddress = 0x3333333333333333333333333333333333333333;
address public rawDataDecoderAndSanitizer = 0x4444444444444444444444444444444444444444;

// Added swap contract address for btc carry strategy
address public swap = 0x9999999999999999999999999999999999999999;

function setUp() external {}

function run() external {
generateAdminStrategistMerkleRoot();
}

function generateAdminStrategistMerkleRoot() public {
setSourceChainName(hyperliquid);
setAddress(false, hyperliquid, "boringVault", boringVault);
setAddress(false, hyperliquid, "managerAddress", managerAddress);
setAddress(false, hyperliquid, "accountantAddress", accountantAddress);
setAddress(false, hyperliquid, "rawDataDecoderAndSanitizer", rawDataDecoderAndSanitizer);

// Initialize leaf array
ManageLeaf[] memory leafs = new ManageLeaf[](32);

// Add Felix leaves
_addFelixLeafs(leafs);

// Add Hyperliquid leaves
_addHyperliquidLeafs(leafs);

// Add swap leaf
unchecked {
leafIndex++;
}
leafs[leafIndex] = ManageLeaf(
swap,
false,
"swap(uint256)",
new address[](0),
"BTC Carry: perform swap",
getAddress(sourceChain, "rawDataDecoderAndSanitizer")
);

_verifyDecoderImplementsLeafsFunctionSelectors(leafs);

string memory filePath = "./leafs/Hyperliquid/hyperBtcCarryAdminLeafs.json";
bytes32[][] memory manageTree = _generateMerkleTree(leafs);
_generateLeafs(filePath, leafs, manageTree[manageTree.length - 1][0], manageTree);
}
}
3 changes: 3 additions & 0 deletions src/base/BoringVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {ERC20} from "@solmate/tokens/ERC20.sol";
import {BeforeTransferHook} from "src/interfaces/BeforeTransferHook.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";

import {console} from "@forge-std/Test.sol";

contract BoringVault is ERC20, Auth, ERC721Holder, ERC1155Holder {
using Address for address;
using SafeTransferLib for ERC20;
Expand Down Expand Up @@ -46,6 +48,7 @@ contract BoringVault is ERC20, Auth, ERC721Holder, ERC1155Holder {
returns (bytes memory result)
{
result = target.functionCallWithValue(data, value);
console.logString("manage done");
}

/**
Expand Down
122 changes: 122 additions & 0 deletions src/base/DecodersAndSanitizers/FelixDecoderAndSanitizer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.21;

import {BaseDecoderAndSanitizer} from "src/base/DecodersAndSanitizers/BaseDecoderAndSanitizer.sol";

enum FelixOperation {
CreateTrove,
AddColl,
WithdrawColl,
WithdrawBold,
RepayBold,
CloseTrove,
AdjustTrove,
ApplyPendingDebt,
ClaimCollateral,
Shutdown
}

contract FelixDecoderAndSanitizer is BaseDecoderAndSanitizer {
// Extract addresses for openTrove for BTC carry strategy using individual parameters
function openTrove(
address owner,
uint256, // ownerIndex
uint256, // ETHAmount
uint256, // boldAmount
uint256, // upperHint
uint256, // lowerHint
uint256, // annualInterestRate
uint256, // maxUpfrontFee
address addManager,
address removeManager,
address receiver
)
external
pure
returns (bytes memory addressesFound)
{
// For openTrove, we extract the addresses: owner, addManager, removeManager, and receiver
addressesFound = abi.encodePacked(owner, addManager, removeManager, receiver);
}

// For the functions below, no address parameters exist so we return an empty bytes array.

function addColl(uint256, uint256) // troveId, ETHAmount
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked();
}

function withdrawColl(uint256, uint256) // troveId, amount
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked();
}

function withdrawBold(uint256, uint256, uint256) // troveId, amount, maxUpfrontFee
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked();
}

function repayBold(uint256, uint256) // troveId, amount
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked();
}

function closeTrove(uint256) // troveId
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked();
}

function adjustTrove(
uint256, // troveId
uint256, // collChange
bool, // isCollIncrease
uint256, // debtChange
bool, // isDebtIncrease
uint256 // maxUpfrontFee
)
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked();
}

function applyPendingDebt(uint256, uint256, uint256) // troveId, lowerHint, upperHint
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked();
}

function claimCollateral()
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked();
}

function shutdown()
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.21;

import {BaseDecoderAndSanitizer} from "src/base/DecodersAndSanitizers/BaseDecoderAndSanitizer.sol";

enum HyperliquidOperation {
DepositUSDC,
SendVaultTransfer,
SendTokenDelegate,
SendSpot,
SendIocOrder,
SendCDeposit,
SendCWithdrawal,
SendUsdClassTransfer
}

contract HyperliquidL1DecoderAndSanitizer is BaseDecoderAndSanitizer {
// For sendVaultTransfer: extract the vault address
function sendVaultTransfer(address vault, bool, uint64) // isDeposit, usd
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked(vault);
}

// For sendTokenDelegate: extract the validator address
function sendTokenDelegate(address validator, uint64, bool) // _wei, isUndelegate
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked(validator);
}

// For sendSpot: extract the destination address
function sendSpot(address destination, uint64, uint64) // token, _wei
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked(destination);
}

// For sendIocOrder: no address parameters, so return empty bytes
function sendIocOrder(uint16, bool, uint64, uint64) // perp, isBuy, limitPx, sz
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked();
}

// For sendCDeposit: no address parameters, so return empty bytes
function sendCDeposit(uint64) // _wei
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked();
}

// For sendCWithdrawal: no address parameters, so return empty bytes
function sendCWithdrawal(uint64) // _wei
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked();
}

// For sendUsdClassTransfer: no address parameters, so return empty bytes
function sendUsdClassTransfer(uint64, bool) // ntl, toPerp
external
pure
returns (bytes memory addressesFound)
{
addressesFound = abi.encodePacked();
}
}
7 changes: 6 additions & 1 deletion src/base/Roles/ManagerWithMerkleVerification.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {Auth, Authority} from "@solmate/auth/Auth.sol";
import {IPausable} from "src/interfaces/IPausable.sol";
import {DroneLib} from "src/base/Drones/DroneLib.sol";

import {console} from "@forge-std/Test.sol";

contract ManagerWithMerkleVerification is Auth, IPausable {
using FixedPointMathLib for uint256;
using SafeTransferLib for ERC20;
Expand Down Expand Up @@ -149,6 +151,7 @@ contract ManagerWithMerkleVerification is Auth, IPausable {
_verifyCallData(
strategistManageRoot, manageProofs[i], decodersAndSanitizers[i], targets[i], values[i], targetData[i]
);
console.logString("Verified");
vault.manage(targets[i], targetData[i], values[i]);
}
if (totalSupply != vault.totalSupply()) {
Expand Down Expand Up @@ -280,6 +283,8 @@ contract ManagerWithMerkleVerification is Auth, IPausable {
bool valueNonZero = value > 0;
bytes32 leaf =
keccak256(abi.encodePacked(decoderAndSanitizer, target, valueNonZero, selector, packedArgumentAddresses));
return MerkleProofLib.verify(proof, root, leaf);
bool res = MerkleProofLib.verify(proof, root, leaf);
console.logBool(res);
return res;
}
}
Loading