Skip to content

Commit

Permalink
chore: make it possible to migrate multiple incentive contracts at on…
Browse files Browse the repository at this point in the history
…ce (#220)
  • Loading branch information
kerber0x authored Aug 15, 2023
1 parent 4327561 commit 8be0687
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 55 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "incentive-factory"
version = "1.0.0"
version = "1.0.1"
authors = ["kaimen-sano <[email protected]>"]
edition.workspace = true
description = "The incentive factory to create all incentives"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,27 +257,27 @@
{
"type": "object",
"required": [
"migrate_incentive"
"migrate_incentives"
],
"properties": {
"migrate_incentive": {
"migrate_incentives": {
"type": "object",
"required": [
"incentive_address"
"code_id"
],
"properties": {
"code_id": {
"description": "The new code ID to migrate the incentive contract to.\n\nIf unspecified, will default to the incentive factory's configured incentive code ID.",
"type": [
"integer",
"null"
],
"description": "The new code ID to migrate the incentive contract to.",
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"incentive_address": {
"description": "The address of the incentive contract",
"type": "string"
"description": "The address of the incentive contract. If unspecified, will migrate all incentive contracts.",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,27 +120,27 @@
{
"type": "object",
"required": [
"migrate_incentive"
"migrate_incentives"
],
"properties": {
"migrate_incentive": {
"migrate_incentives": {
"type": "object",
"required": [
"incentive_address"
"code_id"
],
"properties": {
"code_id": {
"description": "The new code ID to migrate the incentive contract to.\n\nIf unspecified, will default to the incentive factory's configured incentive code ID.",
"type": [
"integer",
"null"
],
"description": "The new code ID to migrate the incentive contract to.",
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"incentive_address": {
"description": "The address of the incentive contract",
"type": "string"
"description": "The address of the incentive contract. If unspecified, will migrate all incentive contracts.",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,10 @@ pub fn execute(
min_unbonding_duration,
max_unbonding_duration,
),
ExecuteMsg::MigrateIncentive {
ExecuteMsg::MigrateIncentives {
incentive_address,
code_id,
} => execute::migrate_incentive(deps, info, incentive_address, code_id),
} => execute::migrate_incentives(deps, incentive_address, code_id),
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,173 @@
use cosmwasm_std::{to_binary, DepsMut, MessageInfo, Response, WasmMsg};
use cosmwasm_std::{to_binary, Addr, CosmosMsg, DepsMut, Order, Response, StdResult, WasmMsg};

use crate::{error::ContractError, state::CONFIG};
use crate::error::ContractError;
use crate::state::INCENTIVE_MAPPINGS;

pub fn migrate_incentive(
pub fn migrate_incentives(
deps: DepsMut,
info: MessageInfo,
incentive_address: String,
code_id: Option<u64>,
incentive_address: Option<String>,
code_id: u64,
) -> Result<Response, ContractError> {
// check that sender has permissions to perform migration
let config = CONFIG.load(deps.storage)?;
if info.sender != config.owner {
return Err(ContractError::Unauthorized);
// migrate only the provided incentive address, otherwise migrate all incentives
let mut res = Response::new().add_attributes(vec![
("method", "migrate_incentives".to_string()),
("code_id", code_id.to_string()),
]);
if let Some(incentive_address) = incentive_address {
Ok(res
.add_attribute("incentive", incentive_address.clone())
.add_message(migrate_incentive_msg(
deps.api.addr_validate(incentive_address.as_str())?,
code_id,
)?))
} else {
let incentives = INCENTIVE_MAPPINGS
.range(deps.storage, None, None, Order::Ascending)
.take(30usize)
.map(|item| {
let (_, incentive_address) = item?;
Ok(incentive_address)
})
.collect::<StdResult<Vec<Addr>>>()?;

for incentive in incentives {
res = res
.add_attribute("incentive", &incentive.clone().to_string())
.add_message(migrate_incentive_msg(
deps.api.addr_validate(incentive.into_string().as_str())?,
code_id,
)?)
}

Ok(res)
}
}

/// Creates a migrate incentive message given a incentive address and code id
fn migrate_incentive_msg(incentive_address: Addr, new_code_id: u64) -> StdResult<CosmosMsg> {
Ok(CosmosMsg::Wasm(WasmMsg::Migrate {
contract_addr: incentive_address.to_string(),
new_code_id,
msg: to_binary(&white_whale::pool_network::incentive::MigrateMsg {})?,
}))
}

#[cfg(test)]
mod tests {
// create test to check the update_config function works properly

use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{attr, Addr, Uint128};

use white_whale::pool_network::asset::{Asset, AssetInfo};
use white_whale::pool_network::incentive_factory::ExecuteMsg::MigrateIncentives;
use white_whale::pool_network::incentive_factory::InstantiateMsg;

use crate::contract::{execute, instantiate};
use crate::state::INCENTIVE_MAPPINGS;

#[test]
fn migrate_single_incentive() {
let mut deps = mock_dependencies();
let info = mock_info("owner", &[]);

// if `code_id` was unspecified, we default to the config incentive code id
let new_code_id = code_id.unwrap_or(config.incentive_code_id);

Ok(Response::default()
.add_attributes(vec![
("action", "migrate_incentive".to_string()),
("incentive_address", incentive_address.clone()),
("new_code_id", new_code_id.to_string()),
])
.add_message(WasmMsg::Migrate {
contract_addr: incentive_address,
new_code_id,
msg: to_binary(&white_whale::pool_network::incentive::MigrateMsg {})?,
}))
let msg = InstantiateMsg {
fee_collector_addr: "fee_collector_addr".to_string(),
fee_distributor_addr: "fee_distributor_addr".to_string(),
create_flow_fee: Asset {
info: AssetInfo::NativeToken {
denom: "native-fee-token".to_string(),
},
amount: Uint128::one(),
},
max_concurrent_flows: 1u64,
incentive_code_id: 123,
max_flow_epoch_buffer: 3600u64,
min_unbonding_duration: 86400u64,
max_unbonding_duration: 259200u64,
};
instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();

for i in 0..3 {
INCENTIVE_MAPPINGS
.save(
deps.as_mut().storage,
("token".to_string() + i.to_string().as_str()).as_bytes(),
&Addr::unchecked("incentive".to_string() + i.to_string().as_str()),
)
.unwrap();
}

let res = execute(
deps.as_mut(),
mock_env(),
mock_info("owner", &[]),
MigrateIncentives {
incentive_address: Some("incentive0".to_string()),
code_id: 456,
},
)
.unwrap();

let expected_attributes = vec![
attr("method", "migrate_incentives"),
attr("code_id", "456"),
attr("incentive", "incentive0"),
];
assert_eq!(res.attributes, expected_attributes);
assert_eq!(res.messages.len(), 1usize);
}
#[test]
fn migrate_multiple_incentives() {
let mut deps = mock_dependencies();
let info = mock_info("owner", &[]);

let msg = InstantiateMsg {
fee_collector_addr: "fee_collector_addr".to_string(),
fee_distributor_addr: "fee_distributor_addr".to_string(),
create_flow_fee: Asset {
info: AssetInfo::NativeToken {
denom: "native-fee-token".to_string(),
},
amount: Uint128::one(),
},
max_concurrent_flows: 1u64,
incentive_code_id: 123,
max_flow_epoch_buffer: 3600u64,
min_unbonding_duration: 86400u64,
max_unbonding_duration: 259200u64,
};
instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();

for i in 0..3 {
INCENTIVE_MAPPINGS
.save(
deps.as_mut().storage,
("token".to_string() + i.to_string().as_str()).as_bytes(),
&Addr::unchecked("incentive".to_string() + i.to_string().as_str()),
)
.unwrap();
}

let res = execute(
deps.as_mut(),
mock_env(),
mock_info("owner", &[]),
MigrateIncentives {
incentive_address: None,
code_id: 456,
},
)
.unwrap();

let expected_attributes = vec![
attr("method", "migrate_incentives"),
attr("code_id", "456"),
attr("incentive", "incentive0"),
attr("incentive", "incentive1"),
attr("incentive", "incentive2"),
];
assert_eq!(res.attributes, expected_attributes);
assert_eq!(res.messages.len(), 3usize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ mod migrate_incentive;
mod update_config;

pub use create_incentive::create_incentive;
pub use migrate_incentive::migrate_incentive;
pub use migrate_incentive::migrate_incentives;
pub use update_config::update_config;
10 changes: 4 additions & 6 deletions packages/white-whale/src/pool_network/incentive_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,11 @@ pub enum ExecuteMsg {
/// If unspecified, the `max_unbonding_duration` will not change.
max_unbonding_duration: Option<u64>,
},
MigrateIncentive {
/// The address of the incentive contract
incentive_address: String,
MigrateIncentives {
/// The address of the incentive contract. If unspecified, will migrate all incentive contracts.
incentive_address: Option<String>,
/// The new code ID to migrate the incentive contract to.
///
/// If unspecified, will default to the incentive factory's configured incentive code ID.
code_id: Option<u64>,
code_id: u64,
},
}

Expand Down

0 comments on commit 8be0687

Please sign in to comment.