Skip to content

Commit

Permalink
Merge branch 'release/v2_contracts' into feat/bonding-manager-whale-lair
Browse files Browse the repository at this point in the history
  • Loading branch information
0xFable committed Apr 18, 2024
2 parents 26ac97f + b5495f1 commit bafcbf1
Show file tree
Hide file tree
Showing 34 changed files with 1,323 additions and 775 deletions.
143 changes: 74 additions & 69 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,88 @@
[![first-timers-only](https://img.shields.io/badge/first--timers--only-friendly-blue.svg?style=flat-square)](https://www.firsttimersonly.com/)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com)


[Discord invite]: https://discord.com/invite/tSxyyCWgYX
[Discord badge]: https://img.shields.io/discord/908044702794801233
[Twitter handle]: https://img.shields.io/twitter/follow/WhiteWhaleDefi.svg?style=social&label=Follow
[Twitter badge]: https://twitter.com/intent/follow?screen_name=WhiteWhaleDefi

## Getting started

To get started with `migaloo-core`, please go through the [contributing guide](./docs/CONTRIBUTING.md) to see the
To get started with `white-whale-core`, please go through the [contributing guide](./docs/CONTRIBUTING.md) to see the
different ways to contribute to the project.

## Resources

1. [Website](https://whitewhale.money/)
2. [LitePaper](https://whitewhale.money/LitepaperV2.pdf)
3. [Docs](https://ww0-1.gitbook.io/migaloo-docs/)
3. [Docs](https://docs.whitewhale.money/white-whale)
4. [Discord](https://discord.com/invite/tSxyyCWgYX)
5. [Twitter](https://twitter.com/WhiteWhaleDefi)
6. [Telegram](https://t.me/whitewhaleofficial)

## V2 Architecture

White Whale V2 is the next iteration of the White Whale protocol V1. Besides minor yet impactful tweaks, functionality wise V2
hasn't changed much from V1. The main difference is the architecture, which makes it easier to integrate with to other
protocols. In V1, the protocol used multiple contracts which makes it complex, factories spawning other contracts and so on.
In V2, the protocol has been simplified significantly and built around singleton contracts. So to get an idea, V1 had 14+ contracts,
while V2 has only 5 contracts.

The following is the V2 architecture, and a general description of each contract:

```mermaid
---
title: White Whale V2
---
flowchart LR
P[Pool Manager] <--> I[Incentive Manager]
P[Pool Manager] --> B[Bonding Manager]
V[Vault Manager] --> B
B --> E[Epoch Manager]
I --> E
click P "https://github.com/White-Whale-Defi-Platform/white-whale-core/tree/release/v2_contracts/contracts/liquidity_hub/pool-manager" "Pool Manager"
click V "https://github.com/White-Whale-Defi-Platform/white-whale-core/tree/release/v2_contracts/contracts/liquidity_hub/vault-manager" "Vault Manager"
click I "https://github.com/White-Whale-Defi-Platform/white-whale-core/tree/release/v2_contracts/contracts/liquidity_hub/incentive-manager" "Incentive Manager"
click B "https://github.com/White-Whale-Defi-Platform/white-whale-core/tree/release/v2_contracts/contracts/liquidity_hub/bonding-manager" "Bonding Manager"
click E "https://github.com/White-Whale-Defi-Platform/white-whale-core/tree/release/v2_contracts/contracts/liquidity_hub/epoch-manager" "Epoch Manager"
```
The direction of the arrows represents the dependencies between the contracts.

### Pool Manager
The Pool Manager is the contract that manages the pools in the protocol. It is responsible for creating pool and handling
swaps. Pool creation is permisionless, meaning anyone can create a pool if the fee is paid. The Pool Manager depends on
both the Incentive and Bonding Managers.

### Vault Manager
The Vault Manager is the contract that manages the vaults in the protocol. It is responsible for creating vaults and performing
flashloan operations. Vault creation is permissionless, meaning anyone can create a vault if the fee is paid. The Vault Manager
depends on the Bonding Manager, as that's where the flashloan fees are sent for distribution.

### Incentive Manager
The Incentive Manager is the contract that manages the incentives in the protocol. It is responsible for creating and
distributing incentives on pools. Incentive creation is permissionless, meaning anyone can create an incentive if the fee is paid.
The Incentive Manager depends on the Epoch Manager, as incentives are distributed based on epochs.

### Bonding Manager
The Bonding Manager is the contract that manages the bonding in the protocol. It is responsible for bonding eligible tokens
and distributing the fees generated by the pools and vaults among the users that bond tokens. The Bonding Manager depends
on the Epoch Manager, as the fee distribution is done based on epochs.

### Epoch Manager
The Epoch Manager is the contract that manages the epochs in the protocol. Its single responsibility is to create the epochs,
which are used by the Incentive and Bonding Managers for distributing incentives and fees.

---
## Deployed contracts

White Whale Migaloo is a protocol that exists across multiple chains. You can find contract addresses for different chain deployments
in the [documentation](https://ww0-1.gitbook.io/migaloo-docs/smart-contracts/deployments).
White Whale is a protocol that exists across multiple chains. You can find contract addresses for different chain deployments
in the [documentation](https://docs.whitewhale.money/white-whale/smart-contracts/liquidity-hub-deployments).

## Building and Deploying Migaloo
## Building and Deploying White Whale

To build and deploy Migaloo's smart contracts, there are a series of deployment scripts under `scripts/`. You need at
least Rust v1.65.0 to compile the contracts.
To build and deploy White Whale's smart contracts, there are a series of deployment scripts under `scripts/`. Alternatively,
there are a few `just` recipes you can take advantage of. You need at least Rust v1.65.0 to compile the contracts.

### Build scripts

Expand All @@ -51,80 +104,32 @@ least Rust v1.65.0 to compile the contracts.
it is customizable by passing the number of kB to the script. For example `check_artifacts_size.sh 400` verifies the
artifacts are under 400 kB.

### Deployment scripts

The deployment scripts are found under `scripts/deployment/`. The following is the structure found on under this folder:

```bash
.
├── deploy_env
│   ├── base_env.sh
│   ├── chain_env.sh
│   ├── mainnets
│   │   ├── chihuahua.env
│   │   ├── juno.env
│   │   └── terra.env
│   ├── mnemonics
│   │   ├── deployer_mnemonic_testnet.txt
│   │   └── deployer_mnemonic.txt
│   └── testnets
│   ├── archway.env
│   ├── injective.env
│   ├── juno.env
│   ├── local.env
│   └── terra.env
├── deploy_liquidity_hub.sh
├── deploy_pool.sh
├── deploy_vault.sh
├── input
│   ├── pool.json
│   └── vault.json
├── output
│   ├── uni-5_liquidity_hub_contracts.json
│   ├── uni-5_pools.json
│   └── uni-5_vaults.json
└── wallet_importer.sh
```

There are three main scripts: `deploy_liquidity_hub.sh`, `deploy_pool.sh` and `deploy_vault.sh`. The rest of the scripts
in there are used as auxiliary scripts by the main three listed before.
### Just recipes

The `deploy_env/` folder contains env files defining the parameters for the blockchain where the deployment is going to occur,
whether it is a mainnet or testnet deployment.
All recipes are found in the `justfile`. To see all available recipes, run `just` or `just --list`. Here are some of them:

The `input/` folder is used for adding json files containing the config parameters when deploying pools or vaults.
The `output/` folder is where the scripts will write the data regarding the deployment, in json format. The name of the file
follows the following nomenclature: `"chain_id"_liquidity_hub_contracts`, `"chain_id"_pools`, `"chain_id"_vaults`.
- `build FEATURE=''` # Builds the whole project with the a feature flag if provided.
- `fmt` # Formats the rust, toml and sh files in the project.
- `get-pools CHAIN` # Extracts the pools from the given chain.
- `schemas` # Generates the schemas for the contracts.

- `deploy_liquidity_hub.sh`: deploys the liquidity hubs. It can deploy the entire LH or parts of it. To learn how to use it,
run the script with the `-h` flag.
- `deploy_pool.sh`: deploys a pool based on the configuration specified at `input/pool.json`. To learn how to use it,
run the script with the `-h` flag.
- `deploy_vault.sh`: deploys a vault based on the configuration specified at `input/vault.json`. To learn how to use it,
run the script with the `-h` flag.

Notice that to deploy a pool or vault you need to have deployed the pool or vault factory respectively.

Here are some examples:
### Deployment scripts

```bash
scripts/deployment/deploy_liquidity_hub.sh -c juno -d all
scripts/deployment/deploy_liquidity_hub.sh -c juno -d vault-network
scripts/deployment/deploy_pool-sh -c juno -p scripts/deployment/input/pool.json
scripts/deployment/deploy_vault-sh -c juno -v scripts/deployment/input/vault.json
```
TODO update deployment scripts for V2.

## Testing Migaloo
## Testing White Whale

To run the tests, run `cargo test`. You can also run `cargo tarpaulin -v` to get test code coverage.
To run the tests, run `cargo test`. You can also run `cargo tarpaulin -v` to get test code coverage. Note that the White Whale
project contains a few feature flags that can be used to run the tests. If you want to run the tests for a particular feature,
run `cargo test --features "feature_name"`.

## Disclaimer

**Use the contracts and the White Whale app at your own risk!**

## Audit

Migaloo core contracts have been audited by [SCV-Security](https://www.scv.services/). The report can be found [here](https://github.com/SCV-Security/PublicReports/blob/main/CW/WhiteWhale/White%20Whale%20-%20Migaloo%20Audit%20Report%20v1.0.pdf).
The White Whale V2 contract's audit is currently in progress.

## Contributing

Expand Down
2 changes: 2 additions & 0 deletions contracts/liquidity_hub/epoch-manager/tests/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use white_whale_std::epoch_manager::epoch_manager::{
};

/// Mocks contract instantiation.
#[allow(dead_code)]
pub(crate) fn mock_instantiation(
deps: DepsMut,
info: MessageInfo,
Expand All @@ -28,6 +29,7 @@ pub(crate) fn mock_instantiation(
}

/// Mocks hook addition.
#[allow(dead_code)]
pub(crate) fn mock_add_hook(deps: DepsMut, info: MessageInfo) -> Result<Response, ContractError> {
let msg = ExecuteMsg::AddHook {
contract_addr: "hook_contract_1".to_string(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ impl TestingSuite {
.unwrap();
}

#[allow(clippy::inconsistent_digit_grouping)]
fn create_epoch_manager(&mut self) {
let epoch_manager_contract = self.app.store_code(epoch_manager_contract());

Expand Down Expand Up @@ -197,6 +198,7 @@ impl TestingSuite {
}

#[track_caller]
#[allow(clippy::too_many_arguments)]
pub(crate) fn instantiate(
&mut self,
whale_lair_addr: String,
Expand Down Expand Up @@ -239,6 +241,7 @@ impl TestingSuite {
}

#[track_caller]
#[allow(clippy::too_many_arguments)]
pub(crate) fn instantiate_err(
&mut self,
whale_lair_addr: String,
Expand Down Expand Up @@ -300,6 +303,7 @@ impl TestingSuite {
}

#[track_caller]
#[allow(clippy::too_many_arguments)]
pub(crate) fn update_config(
&mut self,
sender: Addr,
Expand Down Expand Up @@ -555,7 +559,7 @@ impl TestingSuite {

result(
self.app
.execute_contract(sender, self.epoch_manager_addr.clone(), &msg, &vec![]),
.execute_contract(sender, self.epoch_manager_addr.clone(), &msg, &[]),
);

self
Expand Down Expand Up @@ -584,7 +588,7 @@ impl TestingSuite {
#[track_caller]
pub(crate) fn query_current_epoch(
&mut self,
result: impl Fn(StdResult<EpochResponse>),
mut result: impl FnMut(StdResult<EpochResponse>),
) -> &mut Self {
let current_epoch_response: StdResult<EpochResponse> = self.app.wrap().query_wasm_smart(
&self.epoch_manager_addr,
Expand Down
46 changes: 23 additions & 23 deletions contracts/liquidity_hub/incentive-manager/tests/integration.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
extern crate core;

use std::cell::RefCell;

use cosmwasm_std::{coin, Addr, Coin, Decimal, Uint128};

use incentive_manager::ContractError;
use white_whale_std::incentive_manager::{
Config, Curve, EpochId, Incentive, IncentiveAction, IncentiveParams, IncentivesBy,
LpWeightResponse, Position, PositionAction, RewardsResponse,
Config, Curve, Incentive, IncentiveAction, IncentiveParams, IncentivesBy, LpWeightResponse,
Position, PositionAction, RewardsResponse,
};

use crate::common::suite::TestingSuite;
Expand Down Expand Up @@ -707,6 +705,7 @@ fn expand_incentives() {
}

#[test]
#[allow(clippy::inconsistent_digit_grouping)]
fn close_incentives() {
let lp_denom = "factory/pool/uLP".to_string();

Expand Down Expand Up @@ -790,7 +789,7 @@ fn close_incentives() {
},
)
.query_balance("ulab".to_string(), other.clone(), |balance| {
assert_eq!(balance, Uint128::new(99_999_6000));
assert_eq!(balance, Uint128::new(999_996_000));
})
.manage_incentive(
other.clone(),
Expand All @@ -803,7 +802,7 @@ fn close_incentives() {
},
)
.query_balance("ulab".to_string(), other.clone(), |balance| {
assert_eq!(balance, Uint128::new(100_000_0000));
assert_eq!(balance, Uint128::new(1000_000_000));
});

suite
Expand All @@ -829,7 +828,7 @@ fn close_incentives() {
},
)
.query_balance("ulab".to_string(), other.clone(), |balance| {
assert_eq!(balance, Uint128::new(99_999_6000));
assert_eq!(balance, Uint128::new(999_996_000));
})
// the owner of the contract can also close incentives
.manage_incentive(
Expand All @@ -843,7 +842,7 @@ fn close_incentives() {
},
)
.query_balance("ulab".to_string(), other.clone(), |balance| {
assert_eq!(balance, Uint128::new(100_000_0000));
assert_eq!(balance, Uint128::new(1000_000_000));
});
}

Expand Down Expand Up @@ -1115,15 +1114,16 @@ pub fn update_config() {
}

#[test]
#[allow(clippy::inconsistent_digit_grouping)]
pub fn test_manage_position() {
let lp_denom = "factory/pool/uLP".to_string();

let mut suite = TestingSuite::default_with_balances(vec![
coin(1_000_000_000u128, "uwhale".to_string()),
coin(1_000_000_000u128, "ulab".to_string()),
coin(1_000_000_000u128, "uosmo".to_string()),
coin(1_000_000_000u128, "uwhale"),
coin(1_000_000_000u128, "ulab"),
coin(1_000_000_000u128, "uosmo"),
coin(1_000_000_000u128, lp_denom.clone()),
coin(1_000_000_000u128, "invalid_lp".clone()),
coin(1_000_000_000u128, "invalid_lp"),
]);

let creator = suite.creator();
Expand Down Expand Up @@ -1990,11 +1990,11 @@ fn claim_expired_incentive_returns_nothing() {
let lp_denom = "factory/pool/uLP".to_string();

let mut suite = TestingSuite::default_with_balances(vec![
coin(1_000_000_000u128, "uwhale".to_string()),
coin(1_000_000_000u128, "ulab".to_string()),
coin(1_000_000_000u128, "uosmo".to_string()),
coin(1_000_000_000u128, "uwhale"),
coin(1_000_000_000u128, "ulab"),
coin(1_000_000_000u128, "uosmo"),
coin(1_000_000_000u128, lp_denom.clone()),
coin(1_000_000_000u128, "invalid_lp".clone()),
coin(1_000_000_000u128, "invalid_lp"),
]);

let creator = suite.creator();
Expand Down Expand Up @@ -2136,11 +2136,11 @@ fn test_close_expired_incentives() {
let lp_denom = "factory/pool/uLP".to_string();

let mut suite = TestingSuite::default_with_balances(vec![
coin(1_000_000_000u128, "uwhale".to_string()),
coin(1_000_000_000u128, "ulab".to_string()),
coin(1_000_000_000u128, "uosmo".to_string()),
coin(1_000_000_000u128, "uwhale"),
coin(1_000_000_000u128, "ulab"),
coin(1_000_000_000u128, "uosmo"),
coin(1_000_000_000u128, lp_denom.clone()),
coin(1_000_000_000u128, "invalid_lp".clone()),
coin(1_000_000_000u128, "invalid_lp"),
]);

let creator = suite.creator();
Expand Down Expand Up @@ -2182,18 +2182,18 @@ fn test_close_expired_incentives() {
});
}

let current_id: RefCell<EpochId> = RefCell::new(0u64);
let mut current_id = 0;

// try opening another incentive for the same lp denom, the expired incentive should get closed
suite
.query_current_epoch(|result| {
let epoch_response = result.unwrap();
*current_id.borrow_mut() = epoch_response.epoch.id;
current_id = epoch_response.epoch.id;
})
.query_incentives(None, None, None, |result| {
let incentives_response = result.unwrap();
assert_eq!(incentives_response.incentives.len(), 1);
assert!(incentives_response.incentives[0].is_expired(current_id.borrow().clone()));
assert!(incentives_response.incentives[0].is_expired(current_id));
})
.manage_incentive(
other.clone(),
Expand Down
Loading

0 comments on commit bafcbf1

Please sign in to comment.