Skip to content

Commit

Permalink
Added cw-plus interface (#490)
Browse files Browse the repository at this point in the history
* Added cw-plus interface

* Download wasms exmaple script

* Amended publish scripts

* Update packages/integrations/cw-plus/Cargo.toml

Co-authored-by: Mykhailo Donchenko <91957742+Buckram123@users.noreply.github.com>

* Update .gitignore

Co-authored-by: Mykhailo Donchenko <91957742+Buckram123@users.noreply.github.com>

* Update before_publish.sh

Co-authored-by: Mykhailo Donchenko <91957742+Buckram123@users.noreply.github.com>

* Update packages/integrations/cw-plus/Cargo.toml

Co-authored-by: Mykhailo Donchenko <91957742+Buckram123@users.noreply.github.com>

* To Snake Case

* formatting

* Changelog

---------

Co-authored-by: Mykhailo Donchenko <91957742+Buckram123@users.noreply.github.com>
  • Loading branch information
Kayanski and Buckram123 authored Sep 18, 2024
1 parent c47a10b commit 380bd23
Show file tree
Hide file tree
Showing 20 changed files with 1,531 additions and 2 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ gen_cov_test

**/logs/

docs/book
docs/book

packages/integrations/**/artifacts
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Add a method on `TxHandler` to select instantiation permissions on Wasm upload
- Adds an `upload_wasm` function to CosmosSender to upload wasm code associated to no Contract structure
- Update syn to 2.0
- Added cw-plus orchestrator interface to the repo. Pacing the way for more integrations inside this repository in the future

### Breaking

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ members = [
"test_contracts/*",
"packages/macros/*",
"packages/interchain/*",
"packages/integrations/*",
]
exclude = [
"test_contracts/compatibility-test", # TODO: add new after cw-orch-core 2.0.0 as it's breaking, it shouldn't be compatible
Expand Down
1 change: 1 addition & 0 deletions before_publish.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cargo run --example download-wasms -p cw-plus-orch
44 changes: 44 additions & 0 deletions packages/integrations/cw-plus/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[package]
name = "cw-plus-orch"
version = "0.25.0" # Version of cw-orch that's used
edition = "2021"
description = "cw-orch interfaces for cw-plus base contracts"
license = "Apache-2.0"
repository = "https://github.com/AbstractSDK/cw-orchestrator"
homepage = "https://abstract.money"
documentation = "https://orchestrator.abstract.money"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
cosmwasm-std = { workspace = true }
cw-utils = { workspace = true }
cosmwasm-schema = { version = "2.0.0" }


cw-controllers = { version = "2.0.0" }
cw1 = { version = "2.0.0" }
cw1-subkeys = { version = "2.0.0", features = ["library"] }
cw1-whitelist = { version = "2.0.0", features = ["library"] }
cw3 = { version = "2.0.0" }
cw3-fixed-multisig = { version = "2.0.0", features = ["library"] }
cw3-flex-multisig = { version = "2.0.0", features = ["library"] }
cw4 = { version = "2.0.0" }
cw4-group = { version = "2.0.0", features = ["library"] }
cw4-stake = { version = "2.0.0", features = ["library"] }
cw20 = { version = "2.0.0" }
cw20-base = { version = "2.0.0", features = ["library"] }
cw20-ics20 = { version = "2.0.0", features = ["library"] }

cw-orch-from-interface-derive = { version = "0.1.0", path = "../../macros/from-interface-derive" }

cw-orch = { workspace = true }

[dev-dependencies]
cw-orch-interchain = { workspace = true }
cw-orch = { workspace = true, features = ["daemon"] }
dotenv = "0.15.0"
octocrab = "0.39.0"
pretty_env_logger = "0.5.0"
reqwest = "0.12.7"
tokio.workspace = true
50 changes: 50 additions & 0 deletions packages/integrations/cw-plus/examples/download_wasms.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use cw_orch::anyhow;
use std::{io::Cursor, path::PathBuf, str::FromStr};

pub const CW_PLUS_REPO_OWNER: &str = "CosmWasm";
pub const CW_PLUS_REPO_NAME: &str = "cw-plus";
pub const CW_PLUS_RELEASE_TAG: &str = "v2.0.0";

pub const ALL_CONTRACTS: &[&str] = &[
"cw1_subkeys",
"cw1_whitelist",
"cw3_fixed_multisig",
"cw3_flex_multisig",
"cw4_group",
"cw4_stake",
"cw20_base",
"cw20_ics20",
];

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let crate_dir = env!("CARGO_MANIFEST_DIR");
let artifacts_dir = PathBuf::from_str(crate_dir)?.join("artifacts");

// We create the artifacts directory if non-existent
std::fs::create_dir_all(&artifacts_dir)?;

// We get the release, common for all artifacts
let release = octocrab::instance()
.repos(CW_PLUS_REPO_OWNER, CW_PLUS_REPO_NAME)
.releases()
.get_by_tag(CW_PLUS_RELEASE_TAG)
.await?;

for contract in ALL_CONTRACTS {
let release_file_name = format!("{contract}.wasm");
let file_name = artifacts_dir.join(&release_file_name);

let wasm_asset = release
.assets
.iter()
.find(|asset| asset.name.eq(&release_file_name))
.unwrap();

let response = reqwest::get(wasm_asset.browser_download_url.clone()).await?;
let mut file = std::fs::File::create(file_name)?;
let mut content = Cursor::new(response.bytes().await?);
std::io::copy(&mut content, &mut file)?;
}
Ok(())
}
28 changes: 28 additions & 0 deletions packages/integrations/cw-plus/examples/test_wasm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use cw_orch::daemon::networks::LOCAL_JUNO;
use cw_orch::prelude::*;
use cw_plus_orch::cw1_subkeys::Cw1SubKeys;
use cw_plus_orch::cw1_whitelist::Cw1Whitelist;
use cw_plus_orch::cw20_base::Cw20Base;
use cw_plus_orch::cw20_ics20::Cw20Ics20;
use cw_plus_orch::cw3_fixed_multisig::Cw3FixedMultisig;
use cw_plus_orch::cw3_flex_multisig::Cw3FlexMultisig;
use cw_plus_orch::cw4_group::Cw4Group;
use cw_plus_orch::cw4_stake::Cw4Stake;

fn main() -> cw_orch::anyhow::Result<()> {
dotenv::dotenv()?;
pretty_env_logger::init();

let daemon = Daemon::builder(LOCAL_JUNO).build()?;

Cw1SubKeys::new("cw1_subkeys", daemon.clone()).upload()?;
Cw1Whitelist::new("cw1_whitelist", daemon.clone()).upload()?;
Cw3FixedMultisig::new("cw3_fixed_multisig", daemon.clone()).upload()?;
Cw3FlexMultisig::new("cw3_flex_multisig", daemon.clone()).upload()?;
Cw4Group::new("cw4_group", daemon.clone()).upload()?;
Cw4Stake::new("cw4_stake", daemon.clone()).upload()?;
Cw20Base::new("cw20_base", daemon.clone()).upload()?;
Cw20Ics20::new("cw20_ics20", daemon.clone()).upload()?;

Ok(())
}
122 changes: 122 additions & 0 deletions packages/integrations/cw-plus/src/cw1_subkeys.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use cw_orch::interface;

use cw1_subkeys::contract;
pub use cw1_subkeys::msg::{ExecuteMsg, QueryMsg};
pub use cw1_whitelist::msg::InstantiateMsg;
#[cfg(not(target_arch = "wasm32"))]
pub use interfaces::{AsyncQueryMsgInterfaceFns, ExecuteMsgInterfaceFns, QueryMsgInterfaceFns};

#[interface(InstantiateMsg, ExecuteMsg, QueryMsg, Empty)]
pub struct Cw1SubKeys;

#[cfg(not(target_arch = "wasm32"))]
use cw_orch::prelude::*;

#[cfg(not(target_arch = "wasm32"))]
impl<Chain: CwEnv> Uploadable for Cw1SubKeys<Chain> {
// Return the path to the wasm file
fn wasm(_chain: &ChainInfoOwned) -> WasmPath {
artifacts_dir_from_workspace!()
.find_wasm_path("cw1_subkeys")
.unwrap()
}
// Return a CosmWasm contract wrapper
fn wrapper() -> Box<dyn MockContract<Empty>> {
Box::new(
ContractWrapper::new_with_empty(
contract::execute,
contract::instantiate,
contract::query,
)
.with_migrate(contract::migrate),
)
}
}

#[cfg(not(target_arch = "wasm32"))]
/// Copy messages of the contract to implement cw-orch helpers on Execute([`cw_orch::ExecuteFns`]) and Query([`cw_orch::QueryFns`]) interfaces
mod interfaces {
use super::*;

use cosmwasm_schema::schemars::JsonSchema;

#[derive(cw_orch::ExecuteFns, cw_orch_from_interface_derive::FromInterface)]
enum ExecuteMsgInterface<T = Empty>
where
T: Clone + std::fmt::Debug + PartialEq + JsonSchema,
{
/// Execute requests the contract to re-dispatch all these messages with the
/// contract's address as sender. Every implementation has it's own logic to
/// determine in
// This method is renamed to not conflict with [`CwOrchExecute::execute`]
#[cw_orch(fn_name("execute_requests"))]
Execute {
msgs: Vec<cosmwasm_std::CosmosMsg<T>>,
},
/// Freeze will make a mutable contract immutable, must be called by an admin
Freeze {},
/// UpdateAdmins will change the admin set of the contract, must be called by an existing admin,
/// and only works if the contract is mutable
UpdateAdmins { admins: Vec<String> },

/// Add an allowance to a given subkey (subkey must not be admin)
IncreaseAllowance {
spender: String,
amount: Coin,
expires: Option<cw_utils::Expiration>,
},
/// Decreases an allowance for a given subkey (subkey must not be admin)
DecreaseAllowance {
spender: String,
amount: Coin,
expires: Option<cw_utils::Expiration>,
},

// Setups up permissions for a given subkey.
SetPermissions {
spender: String,
permissions: cw1_subkeys::state::Permissions,
},
}

#[cosmwasm_schema::cw_serde]
#[derive(
cosmwasm_schema::QueryResponses,
cw_orch::QueryFns,
cw_orch_from_interface_derive::FromInterface,
)]
enum QueryMsgInterface<T = Empty>
where
T: Clone + std::fmt::Debug + PartialEq + JsonSchema,
{
/// Shows all admins and whether or not it is mutable
#[returns(cw1_whitelist::msg::AdminListResponse)]
AdminList {},
/// Get the current allowance for the given subkey (how much it can spend)
#[returns(cw1_subkeys::state::Allowance)]
Allowance { spender: String },
/// Get the current permissions for the given subkey (how much it can spend)
#[returns(cw1_subkeys::msg::PermissionsInfo)]
Permissions { spender: String },
/// Checks permissions of the caller on this proxy.
/// If CanExecute returns true then a call to `Execute` with the same message,
/// before any further state changes, should also succeed.
#[returns(cw1::CanExecuteResponse)]
CanExecute {
sender: String,
msg: cosmwasm_std::CosmosMsg<T>,
},
/// Gets all Allowances for this contract
#[returns(cw1_subkeys::msg::AllAllowancesResponse)]
AllAllowances {
start_after: Option<String>,
limit: Option<u32>,
},
/// Gets all Permissions for this contract
#[returns(cw1_subkeys::msg::AllPermissionsResponse)]
AllPermissions {
start_after: Option<String>,
limit: Option<u32>,
},
}
}
81 changes: 81 additions & 0 deletions packages/integrations/cw-plus/src/cw1_whitelist.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use cw_orch::interface;

use cw1_whitelist::contract;
pub use cw1_whitelist::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
#[cfg(not(target_arch = "wasm32"))]
pub use interfaces::{AsyncQueryMsgInterfaceFns, ExecuteMsgInterfaceFns, QueryMsgInterfaceFns};

#[interface(InstantiateMsg, ExecuteMsg, QueryMsg, Empty)]
pub struct Cw1Whitelist;

#[cfg(not(target_arch = "wasm32"))]
use cw_orch::prelude::*;

#[cfg(not(target_arch = "wasm32"))]
impl<Chain: CwEnv> Uploadable for Cw1Whitelist<Chain> {
// Return the path to the wasm file
fn wasm(_chain: &ChainInfoOwned) -> WasmPath {
artifacts_dir_from_workspace!()
.find_wasm_path("cw1_whitelist")
.unwrap()
}
// Return a CosmWasm contract wrapper
fn wrapper() -> Box<dyn MockContract<Empty>> {
Box::new(ContractWrapper::new_with_empty(
contract::execute,
contract::instantiate,
contract::query,
))
}
}

#[cfg(not(target_arch = "wasm32"))]
/// Copy messages of the contract to implement cw-orch helpers on Execute([`cw_orch::ExecuteFns`]) and Query([`cw_orch::QueryFns`]) interfaces
mod interfaces {
use super::*;

use cosmwasm_schema::schemars::JsonSchema;

#[derive(cw_orch::ExecuteFns, cw_orch_from_interface_derive::FromInterface)]
enum ExecuteMsgInterface<T = Empty>
where
T: Clone + std::fmt::Debug + PartialEq + JsonSchema,
{
/// Execute requests the contract to re-dispatch all these messages with the
/// contract's address as sender. Every implementation has it's own logic to
/// determine in
// This method is renamed to not conflict with [`CwOrchExecute::execute`]
#[cw_orch(fn_name("execute_requests"))]
Execute {
msgs: Vec<cosmwasm_std::CosmosMsg<T>>,
},
/// Freeze will make a mutable contract immutable, must be called by an admin
Freeze {},
/// UpdateAdmins will change the admin set of the contract, must be called by an existing admin,
/// and only works if the contract is mutable
UpdateAdmins { admins: Vec<String> },
}

#[cosmwasm_schema::cw_serde]
#[derive(
cosmwasm_schema::QueryResponses,
cw_orch::QueryFns,
cw_orch_from_interface_derive::FromInterface,
)]
enum QueryMsgInterface<T = Empty>
where
T: Clone + std::fmt::Debug + PartialEq + JsonSchema,
{
/// Shows all admins and whether or not it is mutable
#[returns(cw1_whitelist::msg::AdminListResponse)]
AdminList {},
/// Checks permissions of the caller on this proxy.
/// If CanExecute returns true then a call to `Execute` with the same message,
/// before any further state changes, should also succeed.
#[returns(cw1::CanExecuteResponse)]
CanExecute {
sender: String,
msg: cosmwasm_std::CosmosMsg<T>,
},
}
}
Loading

0 comments on commit 380bd23

Please sign in to comment.