Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LiquidStone End-to-End Testing #172

Merged
merged 14 commits into from
Dec 3, 2024
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
6 changes: 6 additions & 0 deletions packages/contracts/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ deploy-plumeTestnet:
resume-plumeTestnet:
$(MAKE) deploy RPC_URL=plumeTestnet EXTRA_FLAGS="--verify --verifier blockscout --verifier-url https://test-explorer.plumenetwork.xyz/api\? --legacy --skip-simulation --slow --resume"

deploy-plume:
$(MAKE) deploy RPC_URL=plume EXTRA_FLAGS="--verify --verifier blockscout --verifier-url https://phoenix-explorer.plumenetwork.xyz/api\? --legacy --skip-simulation --slow"

resume-plume:
$(MAKE) deploy RPC_URL=plume EXTRA_FLAGS="--verify --verifier blockscout --verifier-url https://phoenix-explorer.plumenetwork.xyz/api\? --legacy --skip-simulation --slow --resume"

deploy-arbitrum:
$(MAKE) deploy RPC_URL=arbitrum EXTRA_FLAGS="--verify --slow"

Expand Down
2 changes: 2 additions & 0 deletions packages/contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ polygon = "https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
polygonMumbai = "https://polygon-mumbai.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
bitlayer = "https://rpc.bitlayer.org"
bitlayerTestnet = "https://testnet-rpc.bitlayer.org"
plume = "https://phoenix-rpc.plumenetwork.xyz/${PLUME_API_KEY}"
plumeDevnet = "https://devnet-rpc.plumenetwork.xyz"
plumeTestnet_old = "https://testnet-rpc.plumenetwork.xyz"
plumeTestnet= "https://test-rpc.plumenetwork.xyz"
Expand All @@ -35,6 +36,7 @@ arbitrum = { key = "${ARB_ETHERSCAN_API_KEY}", url = "https://api.arbiscan.io/ap
arbitrumSepolia = { key = "${ARB_SEPOLIA_ETHERSCAN_API_KEY}", url = "https://api-sepolia.arbiscan.io/api", chain=421614 }
bitlayer = { key = "bitlayer", url="https://rpc.bitlayer.org" }
bitlayerTestnet = { key = "bitlayerTestnet", url="https://testnet-scan.bitlayer.org" }
plume = { key = "plume", url = 'https://phoenix-explorer.plumenetwork.xyz/api\?', chain=98865 }
plumeDevnet = { key = "plumeDevnet", url = 'https://devnet-explorer.plumenetwork.xyz/api\?', chain=18230 }
plumeTestnet_old = { key = "plumeTestnet_old", url = 'https://testnet-explorer.plumenetwork.xyz/api\?', chain=161221135 }
plumeTestnet = { key = "plumeTestnet", url = 'https://test-explorer.plumenetwork.xyz/api\?', chain=98864 }
41 changes: 41 additions & 0 deletions packages/contracts/resource/plumeMainnet.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
##
# The Application Configuration for the Plume Mainnet Environment.
##

[evm]
# blockchain id, e.g. plumeMainnet=98865, plumeTestnet=98864, plumeTestnet_old=161221135, plumeDevnet=18230
chain_id = 98865
deploy_mocks = false


[evm.address]
# credbull.cb.id admin/owner (#1)
owner = "0x0fEcd2f7B3EC4BeE8001B4F73df32e7917d8fdE3"
# credbulloper.cb.id operator (#2)
operator = "0xf589233a140F037976f2786C8A4Fba4920EB687b"
# credbullupgrader.cb.id upgrader (#4)
upgrader = "0x3E449960Ba36cB00B728A370F991c658e7cca459"
# credbullassetmgr.cb.id asset manager (#7)
asset_manager = "0x97BE1b79AA9dB55e7235a9dd5E686cc4A26A7959"

# USDC.e token address (Fiat Proxy
usdc_token="0x0F3B6CC558A714ecf4Cc9ec8caFF0b57ECf65890"
# Liquid Continuous Multi Token Vault Proxy
liquid_vault_proxy="0xb89846b74f3B190F6e00fc35B3aFfCDF5d4BB9f9"
# Liquid Continuous Multi Token Vault Impl
liquid_vault_impl="0x8f87E1258d645d948F270221C34202Be0583F29b"


[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
# January 1, 2025 2:00:00 PM UTC = 1735740000
vault_start_timestamp = 1735740000

[services.supabase]
url = ""

# Save the contract deployment details to the database.
update_contract_addresses = false
14 changes: 13 additions & 1 deletion packages/contracts/resource/plumeTestnet.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[evm]
# blockchain id, e.g. plumeTestnet=98864, plumeTestnet_old=161221135, plumeDevnet=18230
chain_id = 98864
deploy_mocks = true
deploy_mocks = false

[evm.address]
# credbull-devops wallets. wallet numbers are 1-based (as opposed to 0-based in anvil)
Expand All @@ -19,12 +19,24 @@ custodian = "0x8561845F6a9511cD8e2daCae77A961e718A77cF6"
upgrader = "0xaD3C004eE1f942BFDA2DA0D2DAaC94d6aC012F75"
# devops asset manager (wallet 7) - public address, okay to share
asset_manager = "0xd097E901FB9B75C2d2f97E142d73fA79C31FcAb3"
# CBL token address - Plume Testnet
cbl_token="0x931Cf9ab674bAbfa7De712EE635b75b5636b4D29"
# USDC.e token address - Plume Testnet
usdc_token="0x401eCb1D350407f13ba348573E5630B83638E30D"
# Liquid Continuous Multi Token Vault Proxy - Plume Testnet
liquid_vault_proxy="0x4B1fC984F324D2A0fDD5cD83925124b61175f5C6"
# Liquid Continuous Multi Token Vault Impl - Plume Testnet
liquid_vault_impl="0x9Db9df1D91c5cdE0c92cf02B9992d42f47028b4A"


[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
# January 1, 2024 2:00:00 PM UTC = 1704117600
vault_start_timestamp = 1704117600


[evm.contracts.upside_vault]
# 2 decimal place percentage (meaining value divided by 100) as integer.
Expand Down
50 changes: 50 additions & 0 deletions packages/contracts/resource/testnetArbSepolia.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 = 421614
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 - Arbitrum Sepolia
cbl_token="0x3Dd53Ec7DFff8cf774391867C83583E634363345"
# USDC token address - Arbitrum Sepolia
usdc_token="0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d"

[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 = ""

# Save the contract deployment details to the database.
update_contract_addresses = false
7 changes: 4 additions & 3 deletions packages/contracts/script/DeployLiquidMultiTokenVault.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,13 @@ contract DeployLiquidMultiTokenVault is TomlConfig {
IERC20Metadata asset,
IYieldStrategy yieldStrategy,
IRedeemOptimizer redeemOptimizer
) public view returns (LiquidContinuousMultiTokenVault.VaultParams memory vaultParams_) {
) public view virtual returns (LiquidContinuousMultiTokenVault.VaultParams memory vaultParams_) {
uint256 fullRateBasisPoints = _tomlConfig.readUint(string.concat(CONTRACT_TOML_KEY, ".full_rate_bps"));
uint256 reducedRateBasisPoints = _tomlConfig.readUint(string.concat(CONTRACT_TOML_KEY, ".reduced_rate_bps"));
uint256 startTimestamp = _startTimestamp();

uint256 scale = 10 ** asset.decimals();
uint256 decimals = asset.decimals();
uint256 scale = 10 ** decimals;

TripleRateContext.ContextParams memory contextParams = TripleRateContext.ContextParams({
fullRateScaled: fullRateBasisPoints * scale / 100,
Expand All @@ -118,7 +119,7 @@ contract DeployLiquidMultiTokenVault is TomlConfig {
}),
frequency: 360,
tenor: 30,
decimals: asset.decimals()
decimals: decimals
});

LiquidContinuousMultiTokenVault.VaultParams memory vaultParams = LiquidContinuousMultiTokenVault.VaultParams({
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/script/utils/generateTsAbis.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function getInheritedFunctions(mainArtifact) {
}

function main() {
const current_path_to_broadcast = path.join(__dirname, '../..', 'broadcast/DeployAndLoadLiquidMultiTokenVault.s.sol'); // data loading variant
const current_path_to_broadcast = path.join(__dirname, '../..', 'broadcast/DeployLiquidMultiTokenVault.s.sol'); // data loading variant
const current_path_to_deployments = path.join(__dirname, '../..', 'broadcast');

const chains = getDirectories(current_path_to_broadcast);
Expand Down
118 changes: 118 additions & 0 deletions packages/contracts/test/src/LiquidStoneNinetyDayTest.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { LiquidContinuousMultiTokenVault } from "@credbull/yield/LiquidContinuousMultiTokenVault.sol";
import { LiquidContinuousMultiTokenVaultTestBase } from "@test/test/yield/LiquidContinuousMultiTokenVaultTestBase.t.sol";

import { CalcSimpleInterest } from "@credbull/yield/CalcSimpleInterest.sol";

import { TestParamSet } from "@test/test/token/ERC1155/TestParamSet.t.sol";

import { IYieldStrategy } from "@credbull/yield/strategy/IYieldStrategy.sol";
import { IRedeemOptimizer } from "@credbull/token/ERC1155/IRedeemOptimizer.sol";
import { DeployLiquidMultiTokenVault } from "@script/DeployLiquidMultiTokenVault.s.sol";

import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

contract DeployLiquidStoneNinetyDay is DeployLiquidMultiTokenVault {
function _createVaultParams(
LiquidContinuousMultiTokenVault.VaultAuth memory vaultAuth,
IERC20Metadata asset,
IYieldStrategy yieldStrategy,
IRedeemOptimizer redeemOptimizer
) public view override returns (LiquidContinuousMultiTokenVault.VaultParams memory vaultParams_) {
LiquidContinuousMultiTokenVault.VaultParams memory vaultParams =
super._createVaultParams(vaultAuth, asset, yieldStrategy, redeemOptimizer);

uint256 scale = 10 ** asset.decimals();
vaultParams.contextParams.tenor = 90;
vaultParams.redeemNoticePeriod = 0;
vaultParams.contextParams.fullRateScaled = 10 * scale;
vaultParams.contextParams.initialReducedRate.interestRate = 0; // zero for less than tenor

return vaultParams;
}
}

contract LiquidStoneNinetyDayTest is LiquidContinuousMultiTokenVaultTestBase {
using TestParamSet for TestParamSet.TestParam[];

function setUp() public virtual override {
DeployLiquidMultiTokenVault _deployVault = new DeployLiquidStoneNinetyDay();
_liquidVault = _deployVault.run(_vaultAuth);

// warp to a "real time" time rather than block.timestamp=1
vm.warp(_liquidVault._vaultStartTimestamp() + 1);

_asset = IERC20Metadata(_liquidVault.asset());
_scale = 10 ** _asset.decimals();

_transferAndAssert(_asset, _vaultAuth.owner, alice, 100_000 * _scale);
_transferAndAssert(_asset, _vaultAuth.owner, bob, 100_000 * _scale);
}

function test__LiquidStoneNinetyDay__VerifyDeployTenor() public view {
assertEq(90, _liquidVault.TENOR(), "tenor incorrect");
}

// TODO - need to implement and test for RetainedAssetsReceive1APY

function test__LiquidStoneNinetyDay__RedeemFullTenor() public {
uint256 depositPeriod = 5;
uint256 redeemPeriod = depositPeriod + _liquidVault.TENOR();
uint256 principal = 105 * _scale;

TestParamSet.TestUsers memory aliceTestUsers = TestParamSet.toSingletonUsers(alice);

TestParamSet.TestParam[] memory testParams = new TestParamSet.TestParam[](1);
testParams[0] =
TestParamSet.TestParam({ principal: principal, depositPeriod: depositPeriod, redeemPeriod: redeemPeriod });

uint256[] memory sharesAtPeriods = _testDepositOnly(aliceTestUsers, _liquidVault, testParams);

uint256 expectedReturns = CalcSimpleInterest.calcInterest(
principal, _liquidVault.rateScaled(), redeemPeriod - depositPeriod, _liquidVault.frequency(), _scale
);

_transferFromTokenOwner(_asset, address(_liquidVault), expectedReturns); // give the vault enough to cover returns

// warp to the redeem period
_warpToPeriod(_liquidVault, redeemPeriod);

vm.prank(alice);
_liquidVault.requestRedeem(sharesAtPeriods[0], alice, alice);

vm.prank(alice);
uint256 assets = _liquidVault.redeem(sharesAtPeriods[0], alice, alice);

assertEq(principal + expectedReturns, assets, "wrong assets returned");
}

function test__LiquidStoneNinetyDay__EarlyRedemptionGivesZeroYield() public {
uint256 depositPeriod = 25;
uint256 earlyRedeemPeriod = depositPeriod + _liquidVault.TENOR() - 1; // less than full tenor period
uint256 principal = 125 * _scale;

TestParamSet.TestUsers memory aliceTestUsers = TestParamSet.toSingletonUsers(alice);

TestParamSet.TestParam[] memory testParams = new TestParamSet.TestParam[](1);
testParams[0] = TestParamSet.TestParam({
principal: principal,
depositPeriod: depositPeriod,
redeemPeriod: earlyRedeemPeriod
});

uint256[] memory sharesAtPeriods = _testDepositOnly(aliceTestUsers, _liquidVault, testParams);

// warp to the redeem period
_warpToPeriod(_liquidVault, earlyRedeemPeriod);

vm.prank(alice);
_liquidVault.requestRedeem(sharesAtPeriods[0], alice, alice);

vm.prank(alice);
uint256 assets = _liquidVault.redeem(sharesAtPeriods[0], alice, alice);

assertEq(principal, assets, "early redemption should give back principal and zero returns");
}
}
2 changes: 2 additions & 0 deletions spikes/spike-liquid-stone/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"verify": "yarn workspace @se-2/foundry verify"
},
"devDependencies": {
"@types/dotenv": "^8.2.3",
"husky": "^9.1.4",
"lint-staged": "^15.2.9"
},
Expand All @@ -44,6 +45,7 @@
"dependencies": {
"@openzeppelin/contracts-upgradeable": "^5.0.2",
"alchemy-sdk": "^3.4.2",
"dotenv": "^16.4.5",
"ethers": "^6.13.3",
"react-tooltip": "^5.28.0"
},
Expand Down
6 changes: 6 additions & 0 deletions spikes/spike-liquid-stone/packages/nextjs/.env.sample
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
NEXT_PUBLIC_NETWORK=localhost

NEXT_PUBLIC_CUSTODIAN=0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC

NEXT_PUBLIC_ALCHEMY_API_KEY=

# Required for Plume Mainnet only
# TODO - do not check this in - API key!
PLUME_API_KEY=
Loading
Loading