Skip to content

Commit

Permalink
CBL TGE Staking campaign (#175)
Browse files Browse the repository at this point in the history
CBL TGE Staking campaign
  • Loading branch information
lucasia authored Dec 3, 2024
1 parent 7420746 commit 43e6e24
Show file tree
Hide file tree
Showing 28 changed files with 1,236 additions and 31 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/ci-dev-sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ jobs:
- name: Run Docker Compose with Background Services
run: docker compose --env-file packages/api/.env up --detach --build --wait

- name: Deploy Credbull Staking Vault
run: yarn deploy
working-directory: packages/contracts
env:
DEPLOY_SCRIPT: "script/DeployStakingVaults.s.sol:DeployStakingVaults"

- name: Deploy Credbull Contracts
run: yarn deploy
working-directory: packages/contracts
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"postinstall": "husky install"
},
"devDependencies": {
"@types/winston": "^2.4.4",
"husky": "^9.0.11",
"lint-staged": "^15.2.7",
"turbo": "^2.0.6"
Expand Down
50 changes: 50 additions & 0 deletions packages/contracts/resource/testnetBaseSepolia.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
##
# The Application Configuration for the TestNet Environment.
##

[evm]
# blockchain id, e.g. baseSepolia=84532, arbSepolia=421614
chain_id = 84532
deploy_mocks = false

[evm.address]
# credbull-devops wallets. wallet numbers are 1-based (as opposed to 0-based in anvil)
# devops admin/owner (wallet 1) - public address, okay to share
owner = "0xD79Be36f61fce3B8EF2FBF22b13B2b9a68eE15A2"
# devops operator (wallet 2) - public address, okay to share
operator = "0xaD3C004eE1f942BFDA2DA0D2DAaC94d6aC012F75"
# devops custodian (wallet 3) - public address, okay to share
custodian = "0x8561845F6a9511cD8e2daCae77A961e718A77cF6"
# devops upgrader (wallet 4) - public address, okay to share
upgrader = "0xaD3C004eE1f942BFDA2DA0D2DAaC94d6aC012F75"
# devops asset manager (wallet 7) - public address, okay to share
asset_manager = "0xd097E901FB9B75C2d2f97E142d73fA79C31FcAb3"
# CBL token address - Base Sepolia
cbl_token="0x2064334877Fac12f353b8FB42440805709eC267A"
# USDC token address - Base Sepolia
usdc_token="0x036CbD53842c5426634e7929541eC2318f3dCF7e"

[evm.contracts.liquid_continuous_multi_token_vault]
# rate in basis points, e.g. 10% = 1000 bps
full_rate_bps = 10_00
# rate in basis points, e.g. 5.5% = 550 bps
reduced_rate_bps = 5_50

[evm.contracts.upside_vault]
# 2 decimal place percentage (meaining value divided by 100) as integer.
collateral_percentage = 200

[evm.contracts.cbl]
# CBL token params
# devops admin/owner (wallet 1) - public address, okay to share
owner = "0xD79Be36f61fce3B8EF2FBF22b13B2b9a68eE15A2"
# devops operator (wallet 2) - public address, okay to share
minter = "0xaD3C004eE1f942BFDA2DA0D2DAaC94d6aC012F75"
# CBL token params
max_supply = 10_000_000 # 10 million in wei

[services.supabase]
url = "https://kyvvhlnmoqibdihqrlmc.supabase.co"

# Save the contract deployment details to the database.
update_contract_addresses = true
6 changes: 3 additions & 3 deletions packages/contracts/script/DeployMocks.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ contract DeployMocks is Script {

if (isTestMode || deployChecker.isDeployRequired("SimpleToken")) {
testToken = new SimpleToken(owner, totalSupply);
console2.log("!!!!! Deploying SimpleToken !!!!!");
console2.log(string.concat("!!!!! Deploying SimpleToken [", vm.toString(address(testToken)), "] !!!!!"));
} else {
testToken = SimpleToken(deployChecker.getContractAddress("SimpleToken"));
}

if (isTestMode || deployChecker.isDeployRequired("SimpleUSDC")) {
testStablecoin = new SimpleUSDC(owner, totalSupply);
console2.log("!!!!! Deploying SimpleToken !!!!!");
console2.log(string.concat("!!!!! Deploying SimpleUSDC [", vm.toString(address(testStablecoin)), "] !!!!!"));
} else {
testStablecoin = SimpleUSDC(deployChecker.getContractAddress("SimpleUSDC"));
}
Expand All @@ -59,7 +59,7 @@ contract DeployMocks is Script {
custodian: custodian
});
testVault = new SimpleVault(params);
console2.log("!!!!! Deploying Simple Vault !!!!!");
console2.log(string.concat("!!!!! Deploying Simple Vault [", vm.toString(address(testVault)), "] !!!!!"));
}

vm.stopBroadcast();
Expand Down
141 changes: 141 additions & 0 deletions packages/contracts/script/DeployStakingVaults.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { Script } from "forge-std/Script.sol";

import { HelperConfig, NetworkConfig } from "@script/HelperConfig.s.sol";

import { CredbullFixedYieldVaultFactory } from "@credbull/CredbullFixedYieldVaultFactory.sol";
import { CredbullFixedYieldVault } from "@credbull/CredbullFixedYieldVault.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Vault } from "@credbull/vault/Vault.sol";
import { MaturityVault } from "@credbull/vault/MaturityVault.sol";
import { FixedYieldVault } from "@credbull/vault/FixedYieldVault.sol";
import { WindowPlugin } from "@credbull/plugin/WindowPlugin.sol";
import { WhiteListPlugin } from "@credbull/plugin/WhiteListPlugin.sol";
import { MaxCapPlugin } from "@credbull/plugin/MaxCapPlugin.sol";

import { console2 } from "forge-std/console2.sol";

contract DeployStakingVaults is Script {
bool private isTestMode;

function runTest()
public
returns (
CredbullFixedYieldVaultFactory factory,
CredbullFixedYieldVault stakingVault50APY_,
CredbullFixedYieldVault stakingVault0APY_,
HelperConfig helperConfig
)
{
isTestMode = true;
return run();
}

function run()
public
returns (
CredbullFixedYieldVaultFactory factory,
CredbullFixedYieldVault stakingVault50APY_,
CredbullFixedYieldVault stakingVault0APY_,
HelperConfig helperConfig
)
{
helperConfig = new HelperConfig(isTestMode);

vm.startBroadcast();

CredbullFixedYieldVault stakingVault50APY = new CredbullFixedYieldVault(
createStakingVaultParams(helperConfig, "inCredbull Earn CBL Staking Challenge", "iceCBLsc", 50)
);
console2.log(
string.concat(
"!!!!! Deploying CredbullFixedYieldVault 50APY [", vm.toString(address(stakingVault50APY)), "] !!!!!"
)
);

CredbullFixedYieldVault stakingVault0APY = new CredbullFixedYieldVault(
createStakingVaultParams(helperConfig, "inCredbull Earn CBL Booster Vault", "iceCBLBooster", 0)
);
console2.log(
string.concat(
"!!!!! Deploying CredbullFixedYieldVault OAPY [", vm.toString(address(stakingVault0APY)), "] !!!!!"
)
);

vm.stopBroadcast();

return (factory, stakingVault50APY, stakingVault0APY, helperConfig);
}

function createStakingVaultParams(
HelperConfig helperConfig,
string memory shareName,
string memory shareSymbol,
uint256 _yieldPercentage
) internal view returns (CredbullFixedYieldVault.FixedYieldVaultParams memory) {
NetworkConfig memory config = helperConfig.getNetworkConfig();
Vault.VaultParams memory _vaultParams = Vault.VaultParams({
asset: IERC20(config.cblToken),
shareName: shareName,
shareSymbol: shareSymbol,
custodian: config.factoryParams.custodian
});

MaturityVault.MaturityVaultParams memory _maturityVaultParams =
MaturityVault.MaturityVaultParams({ vault: _vaultParams });

FixedYieldVault.ContractRoles memory _contractRoles = FixedYieldVault.ContractRoles({
owner: config.factoryParams.owner,
operator: config.factoryParams.operator,
custodian: config.factoryParams.custodian
});

uint256 depositStart = 1730973600; // Deposit Start: Nov 7 10 AM UTC - okay
WindowPlugin.Window memory _depositWindow =
WindowPlugin.Window({ opensAt: depositStart, closesAt: depositStart + 14 days - 1 });

uint256 redeemStart = _depositWindow.closesAt + 30 days + 1; // Withdraw Start: Deposit End + 30 days
WindowPlugin.Window memory _redemptionWindow =
WindowPlugin.Window({ opensAt: (redeemStart), closesAt: (redeemStart + 30 days - 1) });

_logWindowTimestamps(_depositWindow, _redemptionWindow);

WindowPlugin.WindowPluginParams memory _windowPluginParams =
WindowPlugin.WindowPluginParams({ depositWindow: _depositWindow, redemptionWindow: _redemptionWindow });

WhiteListPlugin.WhiteListPluginParams memory _whiteListPluginParams = WhiteListPlugin.WhiteListPluginParams({
whiteListProvider: config.factoryParams.owner, // using owner as the whitelist provider
depositThresholdForWhiteListing: type(uint256).max // logically disable the whitelist
});

uint256 maxCap = 10_000_000 ether;
MaxCapPlugin.MaxCapPluginParams memory _maxCapPluginParams = MaxCapPlugin.MaxCapPluginParams({ maxCap: maxCap }); // Max cap not necessary for staking vaults

return FixedYieldVault.FixedYieldVaultParams({
maturityVault: _maturityVaultParams,
roles: _contractRoles,
windowPlugin: _windowPluginParams,
whiteListPlugin: _whiteListPluginParams,
maxCapPlugin: _maxCapPluginParams,
promisedYield: _yieldPercentage
});
}

//@dev - see https://www.epochconverter.com/batch#results
function _logWindowTimestamps(WindowPlugin.Window memory depositWindow, WindowPlugin.Window memory redemptionWindow)
internal
pure
{
console2.log("===============================================================");
console2.log("Vault windows: depositStart, depositEnd, redeemStart, redeemEnd");
console2.log("===============================================================");
console2.log(depositWindow.opensAt);
console2.log(depositWindow.closesAt);
console2.log(redemptionWindow.opensAt);
console2.log(redemptionWindow.closesAt);
console2.log("===============================================================");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

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

import { HelperConfig } from "@script/HelperConfig.s.sol";
import { DeployStakingVaults } from "@script/DeployStakingVaults.s.sol";
import { CredbullFixedYieldVault } from "@credbull/CredbullFixedYieldVault.sol";

import { CBL } from "@credbull/token/CBL.sol";

contract CredbullFixedYieldVaultStakingTest is Test {
CredbullFixedYieldVault private vault50APY;
CredbullFixedYieldVault private vault0APY;
HelperConfig private helperConfig;

CBL private cbl;

address private alice = makeAddr("alice");
address private bob = makeAddr("bob");

address private owner;
address private operator;
address private minter;

uint256 private precision;
uint256 private constant INITIAL_BALANCE = 1000;

function setUp() public {
DeployStakingVaults deployStakingVaults = new DeployStakingVaults();
(, vault50APY, vault0APY, helperConfig) = deployStakingVaults.run();

cbl = CBL(vault50APY.asset());
precision = 10 ** cbl.decimals();

assertEq(10 ** 18, precision, "should be 10^18");

owner = helperConfig.getNetworkConfig().factoryParams.owner;
operator = helperConfig.getNetworkConfig().factoryParams.operator;
minter = helperConfig.getNetworkConfig().factoryParams.operator;

vm.startPrank(minter);
cbl.mint(alice, INITIAL_BALANCE * precision);
cbl.mint(bob, INITIAL_BALANCE * precision);
vm.stopPrank();

assertEq(INITIAL_BALANCE * precision, cbl.balanceOf(alice), "alice didn't receive CBL");
}

function test__FixedYieldVaultStakingChallenge__Expect50APY() public {
uint256 depositAmount = 10 * precision;
uint256 expectedAssets = ((depositAmount * (100 + 50)) / 100);

depositAndVerify(vault50APY, depositAmount, expectedAssets);
}

function test__FixedYieldVaultStakingChallenge__Expect0APY() public {
uint256 depositAmount = 10 * precision;

depositAndVerify(vault0APY, depositAmount, depositAmount);
}

function depositAndVerify(CredbullFixedYieldVault vault, uint256 depositAmount, uint256 expectedAssets) public {
assertTrue(vault.checkWindow(), "window should be on");

vm.prank(owner);
vault.toggleWindowCheck();
assertFalse(vault.checkWindow(), "window should be off");

vm.startPrank(alice);
cbl.approve(address(vault), depositAmount);
uint256 shares = vault.deposit(depositAmount, alice);
vm.stopPrank();

assertEq(depositAmount, cbl.balanceOf(vault.CUSTODIAN()), "custodian should have the CBL");
assertEq(shares, vault.balanceOf(alice), "alice should have the shares");

assertEq(vault.expectedAssetsOnMaturity(), expectedAssets);
}
}
Loading

0 comments on commit 43e6e24

Please sign in to comment.