diff --git a/app-template/.gitignore b/app-template/.gitignore index a32631e5fc..e5533f1fe2 100644 --- a/app-template/.gitignore +++ b/app-template/.gitignore @@ -7,4 +7,4 @@ Cargo.lock .vscode .idea -typescript/node_modules \ No newline at end of file +state.json \ No newline at end of file diff --git a/app-template/Cargo.toml b/app-template/Cargo.toml index 63593074db..d91875c1b5 100644 --- a/app-template/Cargo.toml +++ b/app-template/Cargo.toml @@ -41,21 +41,22 @@ thiserror = { version = "1.0" } schemars = "0.8" cw-asset = { version = "3.0" } -abstract-core = { version = "0.18.0" } -abstract-app = { version = "0.18.0" } -abstract-sdk = { version = "0.18.0" } +abstract-core = { version = "0.19.0-rc.1" } +abstract-app = { version = "0.19.0-rc.1" } +abstract-sdk = { version = "0.19.0-rc.1" } # Dependencies for interface -abstract-interface = { version = "0.18.0", optional = true } -cw-orch = { version = "0.13.0", optional = true } +abstract-interface = { version = "0.19.0-rc.1", optional = true } +cw-orch = { version = "0.16.3", optional = true } [dev-dependencies] app = { path = ".", features = ["interface"] } -abstract-interface = { version = "0.18.0", features = ["daemon"] } -abstract-testing = { version = "0.18.0" } -abstract-sdk = { version = "0.18.0", features = ["test-utils"] } +abstract-interface = { version = "0.19.0-rc.1", features = ["daemon"] } +abstract-testing = { version = "0.19.0-rc.1" } +abstract-sdk = { version = "0.19.0-rc.1", features = ["test-utils"] } speculoos = "0.11.0" semver = "1.0" dotenv = "0.15.0" env_logger = "0.10.0" -cw-orch = { version = "0.13.0", features = ["daemon"] } +cw-orch = { version = "0.16.3", features = ["daemon"] } +clap = { version = "4.3.7", features = ["derive"] } diff --git a/app-template/README.md b/app-template/README.md index 5ed2a728b0..e6d10da4fd 100644 --- a/app-template/README.md +++ b/app-template/README.md @@ -49,11 +49,22 @@ Here are some of the tasks available in the `justfile`: You can see the full list of tasks available by running `just --list`. +### Testing + +You can test the module using the different provided methods. + +1. **Integration testing:** We provide an integration testing setup [here](./tests/integration.rs). You should use this to set up your environment and test the different execution and query entry-points of your module. Once you are satisfied with the results you can try deploying it to a real chain. +2. **Local Daemon:** Once you have confirmed that your module works as expected you can spin up a local node and deploy Abstract + your app onto the chain. You can do this by running the [test-local](./examples/test-local.rs) example, which uses a locally running juno daemon to deploy to. You can setup local juno using `just juno-local` command. At this point you can also test your front-end with the contracts. + +Once testing is done you can attempt an actual deployment on test and mainnet. + ### Deploying Before attempting to deploy your app you need to add your mnemonic to the `.env` file. **Don't use a mnemonic that has mainnet funds for this.** -You can now use `just deploy` to run the `examples/deploy.rs` script. The script will deploy the app to the juno testnet. You can change the network by changing the `network` variable in the script. +It's also assumed that you have an account and module namespace claimed with this account before performing the deployment. You can read how to do that [here](https://docs.abstract.money/4_get_started/5_account_creation.html). + +You can now use `just deploy {{chain-id}}` to run the [`examples/deploy.rs`](./examples/deploy.rs) script. The script will deploy the app to the networks that you provided. Make sure you have enough funds in your wallet on the different networks you aim to deploy on. ### Generating Typescript Client Code diff --git a/app-template/artifacts/app.wasm b/app-template/artifacts/app.wasm index 0c88238b6f..4c1d11deed 100644 Binary files a/app-template/artifacts/app.wasm and b/app-template/artifacts/app.wasm differ diff --git a/app-template/artifacts/checksums.txt b/app-template/artifacts/checksums.txt index 8a90892c19..2e9a735b9f 100644 --- a/app-template/artifacts/checksums.txt +++ b/app-template/artifacts/checksums.txt @@ -1 +1 @@ -3849868a9cbe2fb82bc7375148784233506ac2e70ed424b33d20061c65ca8c6e app.wasm +fd0a2c3713d9b714e278c5a10932960857fafcc560baf9661ea9eb8142ff90a8 app.wasm diff --git a/app-template/artifacts/checksums_intermediate.txt b/app-template/artifacts/checksums_intermediate.txt index eb611dacef..9ffcd9cae3 100644 --- a/app-template/artifacts/checksums_intermediate.txt +++ b/app-template/artifacts/checksums_intermediate.txt @@ -1 +1 @@ -2a2a39252752ccfff03ad02dca930b6f1831afefb001590fe980867658571b17 /target/wasm32-unknown-unknown/release/app.wasm +401a106d68adbe57c4b83758e8b31f83dc404cb1bac4b64589c6df6b0a181ac9 /target/wasm32-unknown-unknown/release/app.wasm diff --git a/app-template/example.env b/app-template/example.env index 3c18a12b99..16f9ea13bb 100644 --- a/app-template/example.env +++ b/app-template/example.env @@ -6,4 +6,5 @@ LOCAL_MNEMONIC="" TEST_MNEMONIC="" MAIN_MNEMONIC="" -STATE_FILE="state.json" +# Location where state is stored, defaults to ~/cw-orchestrator/state.json (Optional) +# STATE_FILE="./state.json" diff --git a/app-template/examples/deploy.rs b/app-template/examples/deploy.rs index b78768c056..23842e7f2e 100644 --- a/app-template/examples/deploy.rs +++ b/app-template/examples/deploy.rs @@ -1,28 +1,64 @@ +//! Deploys the module to the Abstract platform by uploading it and registering it on the version control contract. +//! +//! This should be used for mainnet/testnet deployments in combination with our front-end at https://app.abstract.money +//! +//! **Requires you to have an account and namespace registered** +//! +//! The mnemonic used to register the module must be the same as the owner of the account that claimed the namespace. +//! +//! Read our docs to learn how: https://docs.abstract.money/4_get_started/5_account_creation.html +//! +//! ## Example +//! +//! ```bash +//! $ just deploy uni-6 osmo-test-5 +//! ``` + +use abstract_interface::AppDeployer; +use app::{ + contract::{APP_ID, APP_VERSION}, + AppInterface, +}; +use clap::Parser; use cw_orch::{ anyhow, + daemon::ChainInfo, prelude::{networks::parse_network, DaemonBuilder}, tokio::runtime::Runtime, }; - -use abstract_interface::AppDeployer; -use app::{contract::APP_ID, AppInterface}; use semver::Version; -const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); +fn deploy(networks: Vec) -> anyhow::Result<()> { + // run for each requested network + for network in networks { + let version: Version = APP_VERSION.parse().unwrap(); + let rt = Runtime::new()?; + let chain = DaemonBuilder::default() + .handle(rt.handle()) + .chain(network) + .build()?; -fn main() -> anyhow::Result<()> { - dotenv().ok(); - env_logger::init(); - let chain = parse_network("juno-1"); - use dotenv::dotenv; - let version: Version = CONTRACT_VERSION.parse().unwrap(); - let rt = Runtime::new()?; - let chain = DaemonBuilder::default() - .chain(chain) - .handle(rt.handle()) - .build()?; - let app = AppInterface::new(APP_ID, chain); + let app = AppInterface::new(APP_ID, chain); + app.deploy(version)?; - app.deploy(version)?; + // Create an account on our front-end to install the module! + // https://app.abstract.money + } Ok(()) } + +#[derive(Parser, Default, Debug)] +#[command(author, version, about, long_about = None)] +struct Arguments { + /// Network Id to deploy on + #[arg(short, long, value_delimiter = ' ', num_args = 1..)] + network_ids: Vec, +} + +fn main() { + dotenv::dotenv().ok(); + env_logger::init(); + let args = Arguments::parse(); + let networks = args.network_ids.iter().map(|n| parse_network(n)).collect(); + deploy(networks).unwrap(); +} diff --git a/app-template/examples/test-local.rs b/app-template/examples/test-local.rs new file mode 100644 index 0000000000..f066ea1901 --- /dev/null +++ b/app-template/examples/test-local.rs @@ -0,0 +1,66 @@ +//! Deploys Abstract and the App module to a local Junod instance. See how to spin up a local chain here: https://docs.junonetwork.io/developer-guides/junod-local-dev-setup +//! You can also start a juno container by running `just juno-local`. +//! +//! Ensure the local juno is running before executing this script. +//! +//! # Run +//! +//! `cargo run --example test-local` + +use abstract_core::objects::gov_type::GovernanceDetails; +use abstract_interface::{Abstract, AppDeployer, VCExecFns}; +use app::{ + contract::{APP_ID, APP_VERSION}, + msg::AppInstantiateMsg, + AppInterface, +}; +use cw_orch::{ + anyhow, + deploy::Deploy, + prelude::{networks::LOCAL_JUNO, Daemon, TxHandler}, + tokio::runtime::Runtime, +}; +use semver::Version; +use speculoos::{assert_that, prelude::BooleanAssertions}; + +const LOCAL_MNEMONIC: &str = "clip hire initial neck maid actor venue client foam budget lock catalog sweet steak waste crater broccoli pipe steak sister coyote moment obvious choose"; + +fn main() -> anyhow::Result<()> { + dotenv::dotenv().ok(); + env_logger::init(); + + let version: Version = APP_VERSION.parse().unwrap(); + let runtime = Runtime::new()?; + + let daemon = Daemon::builder() + .chain(LOCAL_JUNO) + .mnemonic(LOCAL_MNEMONIC) + .handle(runtime.handle()) + .build() + .unwrap(); + // Deploy abstract locally + let abstract_deployment = Abstract::deploy_on(daemon.clone(), daemon.sender().to_string())?; + + let app = AppInterface::new(APP_ID, daemon.clone()); + + // Create account + let account = abstract_deployment.account_factory.create_default_account( + GovernanceDetails::Monarchy { + monarch: daemon.sender().into_string(), + }, + )?; + + // Claim namespace + abstract_deployment + .version_control + .claim_namespace(account.id()?, "my-namespace".to_owned())?; + + // Deploy + app.deploy(version)?; + + // Install app + account.install_app(app, &AppInstantiateMsg {}, None)?; + + assert_that!(account.manager.is_module_installed(APP_ID).unwrap()).is_true(); + Ok(()) +} diff --git a/app-template/justfile b/app-template/justfile index 1a0bedd144..7fccd66bc2 100644 --- a/app-template/justfile +++ b/app-template/justfile @@ -5,6 +5,8 @@ install-tools: cargo install cargo-watch cargo install cargo-limit +## Development Helpers ## + # Build everything build: cargo build --all-features @@ -34,8 +36,20 @@ watch: check: cargo check --all-features -deploy: - cargo run --example deploy --features +juno-local: + docker kill juno_node_1 || true + docker volume rm -f junod_data || true + docker run --rm -d \ + --name juno_node_1 \ + -p 1317:1317 \ + -p 26656:26656 \ + -p 26657:26657 \ + -p 9090:9090 \ + -e STAKE_TOKEN=ujunox \ + -e UNSAFE_CORS=true \ + --mount type=volume,source=junod_data,target=/root \ + ghcr.io/cosmoscontracts/juno:15.0.0 \ + ./setup_and_run.sh juno16g2rahf5846rxzp3fwlswy08fz8ccuwk03k57y # You can add used sender addresses here wasm: #!/usr/bin/env bash @@ -53,20 +67,12 @@ wasm: docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - ${image}:0.12.13 + ${image}:0.14.0 # Generate the schemas for the app contract schema: cargo schema -# Generate the typescript client for the app contract -ts-codegen: schema - (cd typescript && npm run codegen) - -# Publish the typescript sdk -ts-publish: ts-codegen - (cd typescript && npm publish --access public) - # Generate the schemas for this app and publish them to the schemas repository for access in the Abstract frontend publish-schemas namespace name version: schema #!/usr/bin/env bash @@ -108,3 +114,20 @@ publish-schemas namespace name version: schema # Create a pull request using 'gh' CLI tool gh pr create --title 'Add schemas for {{namespace}} {{name}} {{version}}' --body "" + +## Exection commands ## + +run-script script +CHAINS: + cargo run --example {{script}} -- --network-ids {{CHAINS}} + +deploy +CHAINS: + just run-script deploy {{CHAINS}} + +create-account +CHAINS: + just run-script create-account {{CHAINS}} + +claim-namespace +CHAINS: + just run-script claim-namespace {{CHAINS}} + +install-module +CHAINS: + just run-script install-module {{CHAINS}} diff --git a/app-template/src/msg.rs b/app-template/src/msg.rs index e01011340f..db6fa97b7b 100644 --- a/app-template/src/msg.rs +++ b/app-template/src/msg.rs @@ -17,6 +17,7 @@ pub enum AppExecuteMsg { UpdateConfig {}, } +/// App query messages #[cosmwasm_schema::cw_serde] #[cfg_attr(feature = "interface", derive(cw_orch::QueryFns))] #[cfg_attr(feature = "interface", impl_into(QueryMsg))] diff --git a/app-template/tests/integration.rs b/app-template/tests/integration.rs index 68920f8ff5..3a2a55c4e3 100644 --- a/app-template/tests/integration.rs +++ b/app-template/tests/integration.rs @@ -1,8 +1,8 @@ -use abstract_core::{app::BaseInstantiateMsg, objects::gov_type::GovernanceDetails}; -use abstract_interface::{Abstract, AbstractAccount, AppDeployer, VCExecFns, *}; +use abstract_core::objects::{gov_type::GovernanceDetails, AccountId}; +use abstract_interface::{Abstract, AbstractAccount, AppDeployer, VCExecFns}; use app::{ contract::{APP_ID, APP_VERSION}, - msg::{AppInstantiateMsg, ConfigResponse, InstantiateMsg}, + msg::{AppInstantiateMsg, ConfigResponse}, *, }; // Use prelude to get all the necessary imports @@ -21,10 +21,10 @@ fn setup() -> anyhow::Result<(AbstractAccount, Abstract, AppInterfac let mock = Mock::new(&sender); // Construct the counter interface - let contract = AppInterface::new(APP_ID, mock.clone()); + let app = AppInterface::new(APP_ID, mock.clone()); // Deploy Abstract to the mock - let abstr_deployment = Abstract::deploy_on(mock, Empty {})?; + let abstr_deployment = Abstract::deploy_on(mock, sender.to_string())?; // Create a new account to install the app onto let account = @@ -37,25 +37,13 @@ fn setup() -> anyhow::Result<(AbstractAccount, Abstract, AppInterfac // claim the namespace so app can be deployed abstr_deployment .version_control - .claim_namespace(1, "my-namespace".to_string())?; + .claim_namespace(AccountId::local(1), "my-namespace".to_string())?; - contract.deploy(APP_VERSION.parse()?)?; + app.deploy(APP_VERSION.parse()?)?; - account.install_module( - APP_ID, - &InstantiateMsg { - base: BaseInstantiateMsg { - ans_host_address: abstr_deployment.ans_host.addr_str()?, - }, - module: AppInstantiateMsg {}, - }, - None, - )?; + account.install_app(app.clone(), &AppInstantiateMsg {}, None)?; - let modules = account.manager.module_infos(None, None)?; - contract.set_address(&modules.module_infos[1].address); - - Ok((account, abstr_deployment, contract)) + Ok((account, abstr_deployment, app)) } #[test] diff --git a/app-template/tests/wasm.rs b/app-template/tests/wasm.rs index 3b60c5e046..87bbaccc52 100644 --- a/app-template/tests/wasm.rs +++ b/app-template/tests/wasm.rs @@ -15,6 +15,6 @@ fn successful_wasm() { // Construct the counter interface let contract = AppInterface::new(APP_ID, mock); - + // Panics if no path to a .wasm file is found contract.wasm(); } diff --git a/justfile b/justfile index 77253f4220..44388e9a74 100644 --- a/justfile +++ b/justfile @@ -12,7 +12,7 @@ pull repo: # Push the local repo to a specific branch push repo branch: - git subtree pull --prefix={{repo}} {{repo}} {{branch}} + git subtree push --prefix={{repo}} {{repo}} {{branch}} # Run a cargo command in all the workspace repos cargo-all *command: