Skip to content

Commit

Permalink
Merge pull request #4 from yieldnest/feature/ynBNB-mainnet
Browse files Browse the repository at this point in the history
Feature: ynBNB mainnet
  • Loading branch information
xhad authored Sep 15, 2024
2 parents 64c1d07 + 444dbfe commit b60eac0
Show file tree
Hide file tree
Showing 33 changed files with 1,723 additions and 209 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
[submodule "lib/openzeppelin-contracts-upgradeable"]
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
[submodule "lib/synclub-contracts"]
path = lib/synclub-contracts
url = https://github.com/lista-dao/synclub-contracts
15 changes: 15 additions & 0 deletions .solhint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"extends": "solhint:recommended",
"plugins": [],
"rules": {
"avoid-suicide": "error",
"avoid-sha3": "warn",
"compiler-version": ["error", "^0.8.0"],
"func-visibility": ["warn", { "ignoreConstructors": true }],
"reason-string": ["warn", { "maxLength": 64 }],
"not-rely-on-time": "warn",
"state-visibility": "error",
"max-line-length": ["warn", 120],
"no-console": "off"
}
}
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ account :; cast wallet import $(ACCOUNT_NAME) --interactive

local-factory :; forge script script/Deploy.s.sol:DeployVaultFactory \
--private-key $(PRIVATE_KEY) \
--rpc-url $(RPC_URL) \
--broadcast

deploy-factory :; forge script script/Deploy.s.sol:DeployVaultFactory \
Expand Down
97 changes: 95 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,106 @@ See the makefile for deployment scripts. Deploy a factory first, then use it to

## Contract Deployments

### BSC Mainnet
| Name | Address |
|-----------------------|----------------------------------------------|
| ynBNB | [0x304B5845b9114182ECb4495Be4C91a273b74B509](https://bscscan.com/address/0x304B5845b9114182ECb4495Be4C91a273b74B509) |
| slisBNB | [0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B](https://bscscan.com/address/0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B) |
| Vault Factory | [0x8F74AC4a934Db365720fa4A0e7aE62FF2457DE41](https://bscscan.com/address/0x8f74ac4a934db365720fa4a0e7ae62ff2457de41) |
| VaultFactory Impl | [0x53dd506c5fC655634F2ab7ca0c1801a08e0Cb607](https://bscscan.com/address/0x53dd506c5fc655634f2ab7ca0c1801a08e0cb607) |
| SingleVault Imp | [0x80815ee920Bd9d856562633C36D3eB0E43cb15e2](https://bscscan.com/address/0x80815ee920bd9d856562633c36d3eb0e43cb15e2) |
| Timelock | [0xd53044093F757E8a56fED3CCFD0AF5Ad67AeaD4a](https://bscscan.com/address/0xd53044093f757e8a56fed3ccfd0af5ad67aead4a) |
| ProxyAdmin | [0x341932c52C431427c2d759f344a0C5085B0F4576](https://bscscan.com/address/0x341932c52c431427c2d759f344a0c5085b0f4576) |
| Security Council | [0x721688652DEa9Cabec70BD99411EAEAB9485d436](https://bscscan.com/address/0x721688652DEa9Cabec70BD99411EAEAB9485d436) |

### BSC Testnet
| Name | Address |
|-----------------------|----------------------------------------------|
| silsBNB | [0x80815ee920bd9d856562633c36d3eb0e43cb15e2](https://testnet.bscscan.com/address/0x80815ee920bd9d856562633c36d3eb0e43cb15e2) |
| ynBNB | [0x7e87787C22117374Fad2E3E2E8C6159f0875F92e](https://testnet.bscscan.com/address/0x7e87787c22117374fad2e3e2e8c6159f0875f92e) |
| slisBNB | [0x80815ee920Bd9d856562633C36D3eB0E43cb15e2](https://testnet.bscscan.com/address/0x80815ee920bd9d856562633c36d3eb0e43cb15e2) |
| VaultFactory | [0x964C6d4050e052D627b8234CAD9CdF0981E40EB3](https://testnet.bscscan.com/address/0x964C6d4050e052D627b8234CAD9CdF0981E40EB3) |
| SingleVault | [0xa2aE2b28c578Fbd7C18B554E7aA388Bf6694a42c](https://testnet.bscscan.com/address/0xa2aE2b28c578Fbd7C18B554E7aA388Bf6694a42c) |
| ynBNB | [0x7e87787C22117374Fad2E3E2E8C6159f0875F92e](https://testnet.bscscan.com/address/0x7e87787c22117374fad2e3e2e8c6159f0875f92e) |


# Project Deployment Commands
This README provides an overview of the commands used to deploy and interact with the smart contracts in this project. The commands are defined in the Makefile and utilize tools such as forge and cast.

## Commands

### Local Factory Deployment
Deploys the DeployVaultFactory script locally to port 8545 using a private key.
```
make local-factory
```

**Details:**
* Script: `script/Deploy.s.sol:DeployVaultFactory`
* Options:
+ `--private-key $(PRIVATE_KEY)`: Uses the specified private key.
+ `--broadcast`: Broadcasts the transaction.

### Factory Deployment
Deploys the DeployVaultFactory script using an account name.
```
make deploy-factory
```
**Details:**
* Script: `script/Deploy.s.sol:DeployVaultFactory`
* Options:
+ `--account ${ACCOUNT_NAME}`: Uses the specified account name.
+ `--rpc-url ${RPC_URL}`: Connects to the specified RPC URL.
+ `--verify`: Verifies the contract on Etherscan.
+ `--broadcast`: Broadcasts the transaction.

### Create Single Vault
Sends a transaction to create a single vault using the `createSingleVault` function.

**Details:**

* Function: `createSingleVault(address, string, string, address, uint256, address[], address[])`
* Arguments:
+ `address _logic`: `${ASSET_ADDRESS}`
+ `string _name`: `"${VAULT_NAME}"`
+ `string _symbol`: `"${VAULT_SYMBOL}"`
+ `address _admin`: `${ADMIN_ADDRESS}`
+ `uint256 _minDelay`: `${MIN_DELAY}`
+ `address[] _proposers`: `"[${PROPOSER_1},${PROPOSER_2}]"`
+ `address[] _executors`: `"[${EXECUTOR_1},${EXECUTOR_2}]"`
* Options:
+ `--account ${ACCOUNT_NAME}`: Uses the specified account name.
+ `--rpc-url ${RPC_URL}`: Connects to the specified RPC URL.

**Usage:**

To use these commands, ensure you have the necessary environment variables set:
```
export RPC_URL="your_rpc_url"
export ACCOUNT_NAME="your_account_name"
export FACTORY_ADDRESS="your_factory_address"
export ASSET_ADDRESS="your_asset_address"
export VAULT_NAME="your_vault_name"
export VAULT_SYMBOL="your_vault_symbol"
export ADMIN_ADDRESS="your_admin_address"
export MIN_DELAY="your_min_delay"
export PROPOSER_1="your_proposer_1"
export PROPOSER_2="your_proposer_2"
export EXECUTOR_1="your_executor_1"
export EXECUTOR_2="your_executor_2"
make single-vault
```

## Security Notes

There's a loss incurred by the user that's roughly less than `Max(amount, rewards) / 1e18` when he withdraws the exact same shares he received when compared to what he deposited.

I believe this is because of that decimal offset in OZ 46426Upgradeable to prevent donation attacks. The loss maxes out at 10000 wei for 10000 ether amounts so it's small.

1. Deposit Withdraw Scenario
There's a loss incurred by the user that's roughly less than `Max(amount, rewards) / 1e18` when he withdraws the exact same shares he received when compared to what he deposited.

I believe this is because of that decimal offset in OZ 46426Upgradeable to prevent donation attacks. The loss maxes out at 10000 wei for 10000 ether amounts so it's small.

2. Initial Version of the Vault is trusted by the YnBscSecurityCouncil:
https://app.safe.global/home?safe=bnb:0x721688652DEa9Cabec70BD99411EAEAB9485d436
116 changes: 116 additions & 0 deletions broadcast/Deploy.s.sol/56/run-1726284335.json

Large diffs are not rendered by default.

391 changes: 391 additions & 0 deletions broadcast/Deploy.s.sol/56/run-1726284476.json

Large diffs are not rendered by default.

391 changes: 391 additions & 0 deletions broadcast/Deploy.s.sol/56/run-latest.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/synclub-contracts
Submodule synclub-contracts added at a27797
11 changes: 11 additions & 0 deletions script/Actors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,14 @@ contract ChapelActors is IActors {
address public constant EXECUTOR_1 = 0x9f0A34ccb5ba9C71336F0c8Cd6181205928B8404;
address public constant EXECUTOR_2 = 0x9f0A34ccb5ba9C71336F0c8Cd6181205928B8404;
}

contract BscActors is IActors {
address public constant ADMIN = 0x721688652DEa9Cabec70BD99411EAEAB9485d436;
address public constant UNAUTHORIZED = address(0);

address public constant PROPOSER_1 = 0x721688652DEa9Cabec70BD99411EAEAB9485d436;
address public constant PROPOSER_2 = 0x721688652DEa9Cabec70BD99411EAEAB9485d436;

address public constant EXECUTOR_1 = 0x721688652DEa9Cabec70BD99411EAEAB9485d436;
address public constant EXECUTOR_2 = 0x721688652DEa9Cabec70BD99411EAEAB9485d436;
}
8 changes: 8 additions & 0 deletions script/Constants.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.24;

contract ynBNBConstants {
uint256 public constant MIN_DELAY = 84600;
string public constant VAULT_NAME = "YieldNest: BNB Liquid Restaking";
string public constant VAULT_SYMBOL = "ynBNB";
}
25 changes: 17 additions & 8 deletions script/Contracts.sol
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;

interface IContracts {
function DEPLOY_FACTORY() external view returns (address);
function KERNEL_VAULT() external view returns (address);
function KARAK_VAULT() external view returns (address);
contract ChapelContracts {
address public constant ACTORS = 0xbA02225f0fdB684c80ad1e829FC31f048c416Ce6;
address public constant VAULT_FACTORY = 0x964C6d4050e052D627b8234CAD9CdF0981E40EB3;
address public constant SINGLE_VAULT = 0xa2aE2b28c578Fbd7C18B554E7aA388Bf6694a42c;
address public constant KERNEL_VAULT = address(0);
address public constant KARAK_KslisBNB = address(0);
address public constant KARAK_SUPERVISOR = address(0);
address public constant slisBNB = 0x80815ee920Bd9d856562633C36D3eB0E43cb15e2;
}

contract ChapelContracts {
address public constant DEPLOY_FACTORY = 0x964C6d4050e052D627b8234CAD9CdF0981E40EB3;
address public constant KERNEL_VAULT = 0x0000000000000000000000000000000000000000;
address public constant KARAK_VAULT = 0x0000000000000000000000000000000000000000;
contract BscContracts {
address public constant ACTORS = 0x1AA714a271047fA5AAFD190F084b66aA77Ba3562;
address public constant VAULT_FACTORY = 0xf6B9b69B7e13D37D3846698bA2625e404C7586aF;
address public constant SINGLE_VAULT = 0x40020796C11750975aD8758a1F2ab725f6b72Db2;
address public constant KERNEL_VAULT = address(0);
address public constant KARAK_KslisBNB = 0x8529019503c5BD707d8Eb98C5C87bF5237F89135;
address public constant KARAK_VAULT_SUPERVISOR = 0x4a2b015CcB8658998692Db9eD4522B8e846962eD;
address public constant slisBNB = 0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B;
address public constant ListaStakeManager = 0x1adB950d8bB3dA4bE104211D5AB038628e477fE6;
}
26 changes: 22 additions & 4 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ pragma solidity ^0.8.24;
import "lib/forge-std/src/Script.sol";

import {VaultFactory} from "src/VaultFactory.sol";
import {AnvilActors, HoleskyActors, ChapelActors, IActors} from "script/Actors.sol";
import {IVaultFactory} from "src/IVaultFactory.sol";
import {AnvilActors, HoleskyActors, ChapelActors, BscActors, IActors} from "script/Actors.sol";
import {SingleVault} from "src/SingleVault.sol";
import {TransparentUpgradeableProxy} from "src/Common.sol";
import {TransparentUpgradeableProxy, TimelockController} from "src/Common.sol";

contract DeployVaultFactory is Script {
function run() public {
Expand All @@ -30,9 +31,17 @@ contract DeployVaultFactory is Script {
uint256 minDelay = 10; // seconds
deployVaultFactory(actors, minDelay);
}

if (block.chainid == 56) {
vm.startBroadcast();
BscActors actors = new BscActors();
uint256 minDelay = 86400; // 24 hours in seconds
deployVaultFactory(actors, minDelay);
}
}

function deployVaultFactory(IActors actors, uint256 minDelay) internal {
function deployVaultFactory(IActors actors, uint256 minDelay) public returns (address) {
address vaultFactoryImpl = address(new VaultFactory());
address singleVaultImpl = address(new SingleVault());

address[] memory proposers = new address[](2);
Expand All @@ -45,6 +54,15 @@ contract DeployVaultFactory is Script {

address admin = actors.ADMIN();

new VaultFactory(singleVaultImpl, proposers, executors, minDelay, admin);
string memory funcSig = "initialize(address,address,address)";

TimelockController timelock = new TimelockController(minDelay, proposers, executors, admin);

TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
vaultFactoryImpl,
address(timelock),
abi.encodeWithSignature(funcSig, singleVaultImpl, admin, address(timelock))
);
return address(proxy);
}
}
13 changes: 13 additions & 0 deletions script/verify-proxy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This was the script uses to verify the ynBNB TransparentUpgradeableProxy on BscScan
PROXY_CONTRACT_TO_VERIFY=0x304B5845b9114182ECb4495Be4C91a273b74B509

# NOTE: Get the constructor args from Etherscan. You can get this from the Verify and Publish section after it fails, it will tell you what it wants from the contract bytecode
# The last section of the byte code is the constructor. There seems to be a difference between how cast cosntructos abi-encoded data and how Etherscan does.
PROXY_CONSTRUCTOR_DATA=00000000000000000000000080815ee920bd9d856562633c36d3eb0e43cb15e2000000000000000000000000d53044093f757e8a56fed3ccfd0af5ad67aead4a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001e40e12d3d5000000000000000000000000b0b84d294e0c75a6abe60171b70edeb2efd14a1b00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000721688652dea9cabec70bd99411eaeab9485d4360000000000000000000000000000000000000000000000000000000000014a78000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000001f5969656c644e6573743a20424e42204c69717569642052657374616b696e67000000000000000000000000000000000000000000000000000000000000000005796e424e420000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000721688652dea9cabec70bd99411eaeab9485d4360000000000000000000000000000000000000000000000000000000000000001000000000000000000000000721688652dea9cabec70bd99411eaeab9485d43600000000000000000000000000000000000000000000000000000000

forge verify-contract $PROXY_CONTRACT_TO_VERIFY \
--constructor-args $PROXY_CONSTRUCTOR_DATA \
--num-of-optimizations 200 \
--etherscan-api-key $ETHERSCAN_API_KEY \
--rpc-url $RPC_URL \
--watch
3 changes: 2 additions & 1 deletion src/Common.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import {ReentrancyGuardUpgradeable} from
"lib/openzeppelin-contracts-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol";
import {ERC4626Upgradeable} from
"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC4626Upgradeable.sol";
import {IERC20} from "lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol";
import {IERC4626} from "lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
import {IAccessControl} from "lib/openzeppelin-contracts/contracts/access/IAccessControl.sol";
import {ERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import {IStakeManager} from "lib/synclub-contracts/contracts/interfaces/IStakeManager.sol";
import {Math} from "lib/openzeppelin-contracts/contracts/utils/math/Math.sol";

contract Common {}
4 changes: 2 additions & 2 deletions src/ISingleVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ interface ISingleVault is IERC20, IERC4626, IAccessControl {

function initialize(
IERC20 asset_,
string memory name_,
string memory symbol_,
string calldata name_,
string calldata symbol_,
address admin_,
uint256 minDelay_,
address[] calldata proposers_,
Expand Down
45 changes: 45 additions & 0 deletions src/IVaultFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;

import {IERC20, IERC4626, IAccessControl} from "src/Common.sol";

interface IVaultFactory is IAccessControl {
enum VaultType {
SingleAsset,
MultiAsset
}

/**
* @dev Represents a vault with its timelock, name, symbol, and type.
* @param timelock The address of the timelock controller for the vault.
* @param name The name of the vault.
* @param symbol The symbol of the vault.
* @param vaultType The type of the vault, either SingleAsset or MultiAsset.
*/
struct Vault {
address timelock;
string name;
string symbol;
VaultType vaultType;
}

function timelock() external view returns (address);

function singleVaultImpl() external view returns (address);

function multiVaultImpl() external view returns (address);

function initialize(address singleVaultImpl_, address admin, address timelock_) external;

function createSingleVault(
IERC20 asset_,
string memory name_,
string memory symbol_,
address admin_,
uint256 minDelay_,
address[] memory proposers_,
address[] memory executors_
) external returns (address);

function setVaultVersion(address implementation_, VaultType vaultType) external;
}
Loading

0 comments on commit b60eac0

Please sign in to comment.