Skip to content

Commit

Permalink
Merge branch 'main' into nicolas/orc-155-bump-syn-in-cw-orch-fns-deri…
Browse files Browse the repository at this point in the history
…ve-to-2nd-version
  • Loading branch information
Kayanski authored Sep 16, 2024
2 parents bdac8d8 + dafd9b6 commit 6975f00
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 113 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Add methods to set the private key and mnemonic of an existing sender
- Deprecate `authz_granter` and `fee_granter` on `Daemon` struct
- 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

### Breaking
Expand Down
54 changes: 28 additions & 26 deletions cw-orch-daemon/src/core.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
use super::{
cosmos_modules, error::DaemonError, queriers::Node, senders::Wallet, tx_resp::CosmTxResponse,
};
use crate::{
queriers::CosmWasm,
senders::{builder::SenderBuilder, query::QuerySender},
senders::{builder::SenderBuilder, query::QuerySender, tx::TxSender},
DaemonAsyncBuilder, DaemonState,
};

use super::{
cosmos_modules, error::DaemonError, queriers::Node, senders::Wallet, tx_resp::CosmTxResponse,
};

use cosmrs::{
cosmwasm::{MsgExecuteContract, MsgInstantiateContract, MsgMigrateContract},
proto::cosmwasm::wasm::v1::MsgInstantiateContract2,
Expand All @@ -16,7 +14,7 @@ use cosmrs::{
};
use cosmwasm_std::{Addr, Binary, Coin};
use cw_orch_core::{
contract::interface_traits::Uploadable,
contract::{interface_traits::Uploadable, WasmPath},
environment::{
AccessConfig, AsyncWasmQuerier, ChainInfoOwned, ChainState, IndexResponse, Querier,
},
Expand All @@ -33,11 +31,8 @@ use std::{
str::{from_utf8, FromStr},
time::Duration,
};

use tonic::transport::Channel;

use crate::senders::tx::TxSender;

pub const INSTANTIATE_2_TYPE_URL: &str = "/cosmwasm.wasm.v1.MsgInstantiateContract2";

#[derive(Clone)]
Expand Down Expand Up @@ -360,21 +355,7 @@ impl<Sender: TxSender> DaemonAsyncBase<Sender> {

log::debug!(target: &transaction_target(), "Uploading file at {:?}", wasm_path);

let file_contents = std::fs::read(wasm_path.path())?;
let mut e = write::GzEncoder::new(Vec::new(), Compression::default());
e.write_all(&file_contents)?;
let wasm_byte_code = e.finish()?;
let store_msg = cosmrs::cosmwasm::MsgStoreCode {
sender: self.sender().account_id(),
wasm_byte_code,
instantiate_permission: access.map(access_config_to_cosmrs).transpose()?,
};

let result = self
.sender()
.commit_tx(vec![store_msg], None)
.await
.map_err(Into::into)?;
let result = upload_wasm(self.sender(), wasm_path, access).await?;

log::info!(target: &transaction_target(), "Uploading done: {:?}", result.txhash);

Expand All @@ -389,7 +370,28 @@ impl<Sender: TxSender> DaemonAsyncBase<Sender> {
}
}

fn access_config_to_cosmrs(
pub async fn upload_wasm<T: TxSender>(
sender: &T,
wasm_path: WasmPath,
access: Option<AccessConfig>,
) -> Result<CosmTxResponse, DaemonError> {
let file_contents = std::fs::read(wasm_path.path())?;
let mut e = write::GzEncoder::new(Vec::new(), Compression::default());
e.write_all(&file_contents)?;
let wasm_byte_code = e.finish()?;
let store_msg = cosmrs::cosmwasm::MsgStoreCode {
sender: sender.account_id(),
wasm_byte_code,
instantiate_permission: access.map(access_config_to_cosmrs).transpose()?,
};

sender
.commit_tx(vec![store_msg], None)
.await
.map_err(Into::into)
}

pub(crate) fn access_config_to_cosmrs(
access_config: AccessConfig,
) -> Result<cosmrs::cosmwasm::AccessConfig, DaemonError> {
let response = match access_config {
Expand Down
55 changes: 32 additions & 23 deletions cw-orch-daemon/src/senders/cosmos.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
use super::{cosmos_options::CosmosWalletKey, query::QuerySender, tx::TxSender};
use crate::{
env::DaemonEnvVars,
proto::injective::ETHEREUM_COIN_TYPE,
queriers::Bank,
core::parse_cw_coins,
cosmos_modules::{self, auth::BaseAccount},
env::{DaemonEnvVars, LOCAL_MNEMONIC_ENV_NAME, MAIN_MNEMONIC_ENV_NAME, TEST_MNEMONIC_ENV_NAME},
error::DaemonError,
keys::private::PrivateKey,
proto::injective::{InjectiveEthAccount, ETHEREUM_COIN_TYPE},
queriers::{Bank, Node},
tx_broadcaster::{
account_sequence_strategy, assert_broadcast_code_cosm_response, insufficient_fee_strategy,
TxBroadcaster,
},
CosmosOptions, GrpcChannel,
};

use crate::proto::injective::InjectiveEthAccount;
use crate::{
cosmos_modules::{self, auth::BaseAccount},
error::DaemonError,
queriers::Node,
tx_builder::TxBuilder,
tx_resp::CosmTxResponse,
upload_wasm, CosmosOptions, GrpcChannel,
};

#[cfg(feature = "eth")]
use crate::proto::injective::InjectiveSigner;

use crate::{core::parse_cw_coins, keys::private::PrivateKey};
use bitcoin::secp256k1::{All, Secp256k1, Signing};
use cosmos_modules::vesting::PeriodicVestingAccount;
use cosmrs::{
bank::MsgSend,
crypto::secp256k1::SigningKey,
Expand All @@ -32,18 +27,15 @@ use cosmrs::{
};
use cosmwasm_std::{coin, Addr, Coin};
use cw_orch_core::{
environment::{ChainInfoOwned, ChainKind},
contract::WasmPath,
environment::{AccessConfig, ChainInfoOwned, ChainKind},
CoreEnvVars, CwEnvError,
};

use crate::env::{LOCAL_MNEMONIC_ENV_NAME, MAIN_MNEMONIC_ENV_NAME, TEST_MNEMONIC_ENV_NAME};
use bitcoin::secp256k1::{All, Secp256k1, Signing};
use std::{str::FromStr, sync::Arc};

use cosmos_modules::vesting::PeriodicVestingAccount;
use tonic::transport::Channel;

use super::{cosmos_options::CosmosWalletKey, query::QuerySender, tx::TxSender};
#[cfg(feature = "eth")]
use crate::proto::injective::InjectiveSigner;

const GAS_BUFFER: f64 = 1.3;
const BUFFER_THRESHOLD: u64 = 200_000;
Expand Down Expand Up @@ -415,6 +407,23 @@ impl Wallet {
}
}

// Helpers to facilitate some rare operations
impl Wallet {
/// Uploads the `WasmPath` path specifier on chain.
/// The resulting code_id can be extracted from the Transaction result using [cw_orch_core::environment::IndexResponse::uploaded_code_id] and returns the resulting code_id
pub async fn upload_wasm(&self, wasm_path: WasmPath) -> Result<CosmTxResponse, DaemonError> {
self.upload_with_access_config(wasm_path, None).await
}

pub async fn upload_with_access_config(
&self,
wasm_path: WasmPath,
access: Option<AccessConfig>,
) -> Result<CosmTxResponse, DaemonError> {
upload_wasm(self, wasm_path, access).await
}
}

impl QuerySender for Wallet {
type Error = DaemonError;
type Options = CosmosOptions;
Expand Down
8 changes: 7 additions & 1 deletion cw-orch-interchain/examples/doc_daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use cw_orch_interchain::{
/// Others

fn create_daemon_env() -> cw_orch::anyhow::Result<DaemonInterchain> {
// ANCHOR: DAEMON_INTERCHAIN_CREATION
// This will create `Daemon` structures associated with chains `LOCAL_JUNO` and `LOCAL_OSMO`
let mut interchain = DaemonInterchain::new(
vec![(LOCAL_JUNO, None), (LOCAL_OSMO, None)],
&ChannelCreationValidator,
Expand All @@ -14,20 +16,24 @@ fn create_daemon_env() -> cw_orch::anyhow::Result<DaemonInterchain> {
let local_juno: Daemon = interchain.get_chain("testing")?;
let _local_osmo: Daemon = interchain.get_chain("localosmosis")?;

// You can also create your own daemon and add it manually
let local_migaloo = DaemonBuilder::new(LOCAL_MIGALOO)
.state(local_juno.state())
.build()?;
interchain.add_daemons(vec![local_migaloo]);

interchain.add_daemons(vec![local_migaloo]);
// ANCHOR_END: DAEMON_INTERCHAIN_CREATION
Ok(interchain)
}

fn create_starship_env() -> cw_orch::anyhow::Result<DaemonInterchain<Starship>> {
// ANCHOR: STARSHIP_INTERCHAIN_CREATION
let starship = Starship::new(None)?;
let interchain = starship.interchain_env();

let _local_juno: Daemon = interchain.get_chain("juno-1")?;
let _local_osmo: Daemon = interchain.get_chain("osmosis-1")?;
// ANCHOR_END: STARSHIP_INTERCHAIN_CREATION

Ok(interchain)
}
Expand Down
36 changes: 34 additions & 2 deletions docs/src/interchain/integrations/mock.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,39 @@ This function will relay a packets successfully from the receiving chain back th
2. <span style="color:red">⬤</span> On the `destination chain`, it triggers a receive transaction for that packet.
3. <span style="color:purple">⬤</span> On the `source chain`, it finally triggers an acknowledgement transaction with the data the `destination_chain` returned.

The `await_packets` function is very similar except that instead of following a single packet, it follows all packets that are being sent within a transaction. This works in a very similar manner and will never return a timeout transaction. This function is recursive as it will also look for packets inside the receive/ack transactions and also follow their IBC cycle. You can think of this function as going down the rabbit-hole of IBC execution and only returning when all IBC interactions are complete.
The `await_packets` function is very similar except that instead of following a single packet, it follows all packets that are being sent within a transaction. This works in a very similar manner and will allows for testing timeouts on IBC packets. This function is recursive as it will also look for packets inside the receive/ack transactions and also follow their IBC cycles. You can think of this function as going down the rabbit-hole of IBC execution and only returning when all IBC interactions are complete.

Finally, the recommended function is `await_and_check_packets`. This will run `await_packets` and then make sure that the resulting IBC acknowledgments and executions are successful. You can find more live examples <a target="_blank" href="https://github.com/AbstractSDK/cw-orchestrator/blob/dd7238f3108ad38b416171c3b1b2f8a0ce368539/cw-orch-interchain/tests/common/ica_demo.rs">here</a>. Here is an example usage:

```rust,ignore
# use cw_orch_interchain::prelude::*;
# fn main() -> anyhow::Result<()>{
# let mut interchain = MockBech32InterchainEnv::new(
# vec![("juno-1", "juno"), ("osmosis-1", "osmosis")],
# );
# let chain = interchain.get_chain("juno-1")?;
# let contract = Contract::new(chain);
let response = contract.execution_with_ibc_consequences()?;
interchain.await_and_check_packets("juno-1", response)?;
let port_id = PortId::transfer();
let ChannelCreationResult {
interchain_channel,
channel_creation_txs,
} = interchain
.create_channel(
"juno-1",
"osmosis-1",
&port_id,
&port_id,
"ics20-1",
Some(cosmwasm_std::IbcOrder::Unordered)
)?;
# Ok(())
# }
```

## IBC Channel creation

Expand Down Expand Up @@ -90,5 +122,5 @@ cw-orchestrator also provides tooling for creating channels between mock environ
# }
```

- The resulting `interchain_channel` object allows you to identify the channel that was just created. It can be useful to retrieve the channel identifiers for instance
- The resulting `interchain_channel` object allows you to identify the channel that was just created. It can be useful to retrieve the channel identifiers for instance (e.g. `channel-567`)
- The resulting `channel_creation_txs` object allows you to identify the different steps of channel creation as well as the IBC packets sent during this creation. This is very useful to analyze the effects of the channel creation on external contracts and structures.
74 changes: 13 additions & 61 deletions docs/src/interchain/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ In order to interact with your environment using IBC capabilities, you first nee
In this guide, we will create a mock environment for local testing. [↓Click here, if you want to interact with actual nodes](#with-actual-cosmos-sdk-nodes).

With mock chains, you can create a mock environment simply by specifying chains ids and sender addresses.
For this guide, we will create 2 chains, `juno` and `osmosis`, with the same address as sender:
For this guide, we will create 2 chains, `juno-1` and `osmosis-1`, with respective address prefixes:

```rust,ignore
let sender = Addr::unchecked("sender_for_all_chains");
let interchain = MockInterchainEnv::new(vec![("juno", &sender), ("osmosis", &sender)]);
let interchain = MockBech32InterchainEnv::new(vec![("juno-1", "juno"), ("osmosis-1", "osmosis")]);
```

### Interacting with the environment
Expand All @@ -24,8 +23,8 @@ The `client` will send IBC messages to the `host` that in turn will execute the
Let's first create the contracts:

```rust,ignore
let juno = interchain.chain("juno")?;
let osmosis = interchain.chain("osmosis")?;
let juno = interchain.chain("juno-1")?;
let osmosis = interchain.chain("osmosis-1")?;
let client = Client::new("test:client", juno.clone());
let host = Host::new("test:host", osmosis.clone());
Expand Down Expand Up @@ -131,10 +130,10 @@ impl<Chain> Uploadable for Host<Chain> {
Then, we can create an IBC channel between the two contracts:

```rust,ignore
let channel_receipt = interchain.create_contract_channel(&client, &host, None, "simple-ica-v2").await?;
let channel_receipt: ChannelCreationResult<_> = interchain.create_contract_channel(&client, &host, None, "simple-ica-v2").await?;
// After channel creation is complete, we get the channel id, which is necessary for ICA remote execution
let juno_channel = channel.0.get_chain("juno")?.channel.unwrap();
let juno_channel = channel_receipt.interchain_channel.get_chain("juno-1")?.channel.unwrap();
```

This step will also await until all the packets sent during channel creation are relayed. In the case of the ICA contracts, a <a href="https://github.com/confio/cw-ibc-demo/blob/main/contracts/simple-ica-controller/src/ibc.rs#L54" target="_blank">`{"who_am_i":{}}`</a> packet is sent out right after channel creation and allows to identify the calling chain.
Expand All @@ -153,30 +152,10 @@ let tx_response = client.send_msgs(
)?;
```

Now, we need to wait for the IBC execution to take place and the relayers to relay the packets. This is done through:
Now, we need to wait for the IBC execution to take place and the relayers to relay the packets. This will also verify that the IBC execution is successful. This is done through:

```rust,ignore
let packet_lifetime = interchain.wait_ibc("juno", tx_response).await?;
```

After that step, we make sure that the packets were relayed correctly

```rust,ignore
// For testing a successful outcome of the first packet sent out in the tx, you can use:
if let IbcPacketOutcome::Success{
ack,
..
} = packet_lifetime.packets[0].outcome{
if let IbcPacketAckDecode::Success(_) = ack{
/// Packet has been successfully acknowledged and decoded, the transaction has gone through correctly
}
/// Else, there was a decode error (maybe you are using the wrong acknowledgement format)
}else{
/// Else the packet timed-out, you may have a relayer error or something is wrong in your application
};
// OR you can use a helper, that will only error if one of the packets being relayed failed
assert_packets_success_decode(packet_lifetime)?;
let packet_lifetime = interchain.await_and_check_packets("juno-1", tx_response).await?;
```

If it was relayed correctly, we can proceed with our application.
Expand All @@ -189,29 +168,10 @@ With this simple guide, you should be able to test and debug your IBC applicatio
You can also create an interchain environment that interacts with actual running chains. Keep in mind in that case that this type of environment doesn't allow channel creation. This step will have to be done manually with external tooling. If you're looking to test your application in a full local test setup, please turn to [↓Starship](#with-starship)

```rust,ignore
use cw_orch::prelude::*;
use cw_orch::tokio;
use cw_orch::prelude::*;
// This is used to deal with async functions
let rt = tokio::runtime::Runtime::new().unwrap();
{{#include ../../../cw-orch-interchain/examples/doc_daemon.rs:DAEMON_INTERCHAIN_CREATION}}
// We create the daemons ourselves to interact with actual running chains (testnet here)
let juno = Daemon::builder(cw_orch::daemon::networks::UNI_6)
.build()
.unwrap();
// We create the daemons ourselves to interact with actual running chains (testnet here)
let osmosis = Daemon::builder(cw_orch::daemon::networks::OSMO_5)
.build()
.unwrap();
// This will allow us to follow packets execution between juno and osmosis
let interchain = DaemonInterchain::from_daemons(
vec![juno, osmosis],
&ChannelCreationValidator,
);
// In case one wants to analyze packets between more chains, you just need to add them to the interchain object
```

With this setup, you can now resume this quick-start guide from [↑Interacting with the environment](#interacting-with-the-environment).
Expand All @@ -226,17 +186,9 @@ Check out <a href="https://docs.cosmology.zone/starship" target="_blank">the off
Once starship is setup and all the ports forwarded, assuming that starship was run locally, you can execute the following:

```rust,ignore
use cw_orch::prelude::*;
use cw_orch::tokio;
// This is used to deal with async functions
let rt = tokio::runtime::Runtime::new().unwrap();
// This is the starship adapter
let starship = Starship::new(None).unwrap();
// You have now an interchain environment that you can use in your application
let interchain = starship.interchain_env();
use cw_orch::prelude::*;
{{#include ../../../cw-orch-interchain/examples/doc_daemon.rs:STARSHIP_INTERCHAIN_CREATION}}
```

This snippet will identify the local Starship setup and initialize all helpers and information needed for interaction using cw-orchestrator.
Expand Down

0 comments on commit 6975f00

Please sign in to comment.