Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nicolas/orc 67 no way to set hd index #306

Merged
merged 31 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
07f4bae
Added cw-multi-test 0.20.0
Kayanski Jan 12, 2024
1c6d09b
Removed secp, removed ibc-relayer-types
Kayanski Jan 12, 2024
9c3bfdc
Removed ibc-relayer-types completely
Kayanski Jan 12, 2024
a56bb35
updated prost typesé
Kayanski Jan 12, 2024
c7ca93c
Start testing authz
Kayanski Jan 12, 2024
049d2e9
Merge branch 'update/cw-multi-test-20' into feature/add-authz-wrapping
Kayanski Jan 12, 2024
4d02ed5
Added authz test
Kayanski Jan 12, 2024
533f1af
Merge remote-tracking branch 'origin/main' into feature/add-authz-wra…
Kayanski Jan 12, 2024
33dc9b8
Added hd path index change inside sender and daemon
Kayanski Jan 12, 2024
5d97ca5
Fixed sender options usageé
Kayanski Jan 12, 2024
da502a0
add authz querier
Buckram123 Jan 17, 2024
5595d47
Merge branch 'main' into feature/add-authz-wrapping
Kayanski Jan 17, 2024
6630b4d
Merge branch 'feature/add-authz-wrapping' of github.com:AbstractSDK/c…
Kayanski Jan 17, 2024
d23d0f7
tx handler error with anyhow test
Buckram123 Jan 17, 2024
e07abdc
Merge remote-tracking branch 'origin/main' into feature/add-authz-wra…
Buckram123 Jan 17, 2024
5b7ebb2
format
Buckram123 Jan 17, 2024
6da5a3d
Merge branch 'feature/add-authz-wrapping' of github.com:AbstractSDK/c…
Kayanski Jan 18, 2024
814066f
Added authz builder method for options
Kayanski Jan 18, 2024
05e321b
Some nits
Kayanski Jan 18, 2024
6e70d1f
Revert with_authz, added sender options setter
Kayanski Jan 18, 2024
10b52a8
Check rest of authz queries
Buckram123 Jan 18, 2024
52d29ae
Added fee grant in daemon builder and interface
Kayanski Jan 19, 2024
2c19a89
Merge branch 'feature/add-authz-wrapping' of github.com:AbstractSDK/c…
Kayanski Jan 19, 2024
f8d8f4f
Merged with authz branch
Kayanski Jan 19, 2024
b4f9418
Refactor daemon for simplified re-builderé
Kayanski Jan 24, 2024
28965db
Modifed async daemon as well
Kayanski Jan 24, 2024
285cafb
Merge with authz
Kayanski Jan 24, 2024
e4fb579
Merge with main
Kayanski Jan 29, 2024
344acd9
Added docs for builder + nits
Kayanski Jan 29, 2024
426ce14
Merge remote-tracking branch 'origin/main' into nicolas/orc-67-no-way…
Kayanski Feb 1, 2024
71f4614
Format
Kayanski Feb 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions cw-orch-daemon/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{log::print_if_log_disabled, DaemonAsync, DaemonBuilder};
use crate::{log::print_if_log_disabled, sender::SenderOptions, DaemonAsync, DaemonBuilder};
use std::rc::Rc;

use ibc_chain_registry::chain::ChainData;
Expand Down Expand Up @@ -28,6 +28,8 @@
pub(crate) deployment_id: Option<String>,
/// Wallet mnemonic
pub(crate) mnemonic: Option<String>,
/// Sender specific options
pub sender_options: SenderOptions,
}

impl DaemonAsyncBuilder {
Expand All @@ -53,6 +55,18 @@
self
}

/// Specifies wether authz should be used with this daemon
pub fn with_authz(&mut self, granter: impl ToString) -> &mut Self {
self.sender_options.authz_granter = Some(granter.to_string());
self
}

Check warning on line 62 in cw-orch-daemon/src/builder.rs

View check run for this annotation

Codecov / codecov/patch

cw-orch-daemon/src/builder.rs#L60-L62

Added lines #L60 - L62 were not covered by tests

/// Specifies the index of the key used for the mnemonic account
pub fn with_index(&mut self, index: u32) -> &mut Self {
self.sender_options.index = Some(index);

Check warning on line 66 in cw-orch-daemon/src/builder.rs

View check run for this annotation

Codecov / codecov/patch

cw-orch-daemon/src/builder.rs#L65-L66

Added lines #L65 - L66 were not covered by tests
self
}

/// Build a daemon
pub async fn build(&self) -> Result<DaemonAsync, DaemonError> {
let chain = self
Expand All @@ -65,10 +79,11 @@
.unwrap_or(DEFAULT_DEPLOYMENT.to_string());
let state = Rc::new(DaemonState::new(chain, deployment_id, false).await?);
// if mnemonic provided, use it. Else use env variables to retrieve mnemonic
let sender_options = self.sender_options.clone();
let sender = if let Some(mnemonic) = &self.mnemonic {
Sender::from_mnemonic(&state, mnemonic)?
Sender::from_mnemonic_with_options(&state, mnemonic, sender_options)?
} else {
Sender::new(&state)?
Sender::new_with_options(&state, sender_options)?
};
let daemon = DaemonAsync {
state,
Expand All @@ -85,6 +100,7 @@
chain: value.chain,
deployment_id: value.deployment_id,
mnemonic: value.mnemonic,
sender_options: value.sender_options,
}
}
}
8 changes: 4 additions & 4 deletions cw-orch-daemon/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl DaemonAsync {
contract_address: &Addr,
) -> Result<CosmTxResponse, DaemonError> {
let exec_msg: MsgExecuteContract = MsgExecuteContract {
sender: self.sender.pub_addr()?,
sender: self.sender.message_sender()?,
contract: AccountId::from_str(contract_address.as_str())?,
msg: serde_json::to_vec(&exec_msg)?,
funds: parse_cw_coins(coins)?,
Expand All @@ -132,7 +132,7 @@ impl DaemonAsync {
code_id,
label: Some(label.unwrap_or("instantiate_contract").to_string()),
admin: admin.map(|a| FromStr::from_str(a.as_str()).unwrap()),
sender: sender.pub_addr()?,
sender: self.sender.message_sender()?,
msg: serde_json::to_vec(&init_msg)?,
funds: parse_cw_coins(coins)?,
};
Expand Down Expand Up @@ -169,7 +169,7 @@ impl DaemonAsync {
contract_address: &Addr,
) -> Result<CosmTxResponse, DaemonError> {
let exec_msg: MsgMigrateContract = MsgMigrateContract {
sender: self.sender.pub_addr()?,
sender: self.sender.message_sender()?,
contract: AccountId::from_str(contract_address.as_str())?,
msg: serde_json::to_vec(&migrate_msg)?,
code_id: new_code_id,
Expand Down Expand Up @@ -243,7 +243,7 @@ impl DaemonAsync {
e.write_all(&file_contents)?;
let wasm_byte_code = e.finish()?;
let store_msg = cosmrs::cosmwasm::MsgStoreCode {
sender: sender.pub_addr()?,
sender: self.sender.message_sender()?,
wasm_byte_code,
instantiate_permission: None,
};
Expand Down
69 changes: 63 additions & 6 deletions cw-orch-daemon/src/sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::{core::parse_cw_coins, keys::private::PrivateKey};
use cosmrs::{
bank::MsgSend,
crypto::secp256k1::SigningKey,
proto::traits::Message,
proto::{cosmos::authz::v1beta1::MsgExec, traits::Message},
tendermint::chain::Id,
tx::{self, ModeInfo, Msg, Raw, SignDoc, SignMode, SignerInfo},
AccountId, Any,
Expand All @@ -48,14 +48,30 @@ pub type Wallet = Rc<Sender<All>>;

/// Signer of the transactions and helper for address derivation
/// This is the main interface for simulating and signing transactions
#[derive(Clone)]
pub struct Sender<C: Signing + Context> {
pub private_key: PrivateKey,
pub secp: Secp256k1<C>,
pub(crate) daemon_state: Rc<DaemonState>,
pub(crate) options: SenderOptions,
}

#[derive(Default, Clone)]
#[non_exhaustive]
pub struct SenderOptions {
pub authz_granter: Option<String>,
pub index: Option<u32>,
}

impl Sender<All> {
pub fn new(daemon_state: &Rc<DaemonState>) -> Result<Sender<All>, DaemonError> {
Self::new_with_options(daemon_state, SenderOptions::default())
}

pub fn new_with_options(
daemon_state: &Rc<DaemonState>,
options: SenderOptions,
) -> Result<Sender<All>, DaemonError> {
let kind = ChainKind::from(daemon_state.chain_data.network_type.clone());
// NETWORK_MNEMONIC_GROUP
let env_variable_name = kind.mnemonic_env_variable_name();
Expand All @@ -66,22 +82,37 @@ impl Sender<All> {
)
});

Self::from_mnemonic(daemon_state, &mnemonic)
Self::from_mnemonic_with_options(daemon_state, &mnemonic, options)
}

/// Construct a new Sender from a mnemonic
/// Construct a new Sender from a mnemonic with additional options
pub fn from_mnemonic(
daemon_state: &Rc<DaemonState>,
mnemonic: &str,
) -> Result<Sender<All>, DaemonError> {
Self::from_mnemonic_with_options(daemon_state, mnemonic, SenderOptions::default())
}

/// Construct a new Sender from a mnemonic with additional options
pub fn from_mnemonic_with_options(
daemon_state: &Rc<DaemonState>,
mnemonic: &str,
options: SenderOptions,
) -> Result<Sender<All>, DaemonError> {
let secp = Secp256k1::new();
let p_key: PrivateKey =
PrivateKey::from_words(&secp, mnemonic, 0, 0, daemon_state.chain_data.slip44)?;
let p_key: PrivateKey = PrivateKey::from_words(
&secp,
mnemonic,
0,
options.index.unwrap_or(0),
daemon_state.chain_data.slip44,
)?;

let sender = Sender {
daemon_state: daemon_state.clone(),
private_key: p_key,
secp,
options,
};
log::info!(
target: &local_target(),
Expand All @@ -92,6 +123,10 @@ impl Sender<All> {
Ok(sender)
}

pub fn with_authz(&mut self, granter: impl Into<String>) {
self.options.authz_granter = Some(granter.into());
}

fn cosmos_private_key(&self) -> SigningKey {
SigningKey::from_slice(&self.private_key.raw_key()).unwrap()
}
Expand All @@ -115,13 +150,21 @@ impl Sender<All> {
Ok(self.pub_addr()?.to_string())
}

pub fn message_sender(&self) -> Result<AccountId, DaemonError> {
if let Some(sender) = &self.options.authz_granter {
Ok(sender.parse()?)
} else {
self.pub_addr()
}
}

pub async fn bank_send(
&self,
recipient: &str,
coins: Vec<cosmwasm_std::Coin>,
) -> Result<CosmTxResponse, DaemonError> {
let msg_send = MsgSend {
from_address: self.pub_addr()?,
from_address: self.message_sender()?,
to_address: AccountId::from_str(recipient)?,
amount: parse_cw_coins(&coins)?,
};
Expand Down Expand Up @@ -239,6 +282,20 @@ impl Sender<All> {
) -> Result<CosmTxResponse, DaemonError> {
let timeout_height = Node::new(self.channel()).block_height().await? + 10u64;

let msgs = if self.options.authz_granter.is_some() {
// We wrap authz messages
vec![Any {
type_url: "/cosmos.authz.v1beta1.MsgExec".to_string(),
value: MsgExec {
grantee: self.pub_addr_str()?,
msgs,
}
.encode_to_vec(),
}]
} else {
msgs
};

let tx_body = TxBuilder::build_body(msgs, memo, timeout_height);

let tx_builder = TxBuilder::new(tx_body);
Expand Down
16 changes: 15 additions & 1 deletion cw-orch-daemon/src/sync/builder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use ibc_chain_registry::chain::ChainData;

use crate::DaemonAsyncBuilder;
use crate::{sender::SenderOptions, DaemonAsyncBuilder};

use super::{super::error::DaemonError, core::Daemon};

Expand All @@ -24,6 +24,8 @@ pub struct DaemonBuilder {
pub(crate) deployment_id: Option<String>,
/// Wallet mnemonic
pub(crate) mnemonic: Option<String>,
/// Sender specific options
pub sender_options: SenderOptions,
}

impl DaemonBuilder {
Expand Down Expand Up @@ -64,6 +66,18 @@ impl DaemonBuilder {
self
}

/// Specifies wether authz should be used with this daemon
pub fn with_authz(&mut self, granter: impl ToString) -> &mut Self {
self.sender_options.authz_granter = Some(granter.to_string());
self
}

/// Specifies the index of the key used for the mnemonic account
pub fn with_index(&mut self, index: u32) -> &mut Self {
self.sender_options.index = Some(index);
self
}

/// Build a Daemon
pub fn build(&self) -> Result<Daemon, DaemonError> {
let rt_handle = self
Expand Down
9 changes: 9 additions & 0 deletions cw-orch-daemon/src/sync/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ impl Daemon {
pub fn wallet(&self) -> Wallet {
self.daemon.sender.clone()
}

// Adds authz capability to the returned Daemon
pub fn with_authz(&self, granter: impl ToString) -> Self {
let mut new_daemon = self.clone();
let mut new_sender = (*self.daemon.sender).clone();
new_sender.with_authz(granter.to_string());
new_daemon.daemon.sender = Rc::new(new_sender);
new_daemon
}
}

impl ChainState for Daemon {
Expand Down
101 changes: 101 additions & 0 deletions cw-orch-daemon/tests/authz.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
mod common;
#[cfg(feature = "node-tests")]
mod tests {
/*
DaemonAsync contract general tests
*/

use cosmrs::proto::cosmos::{
authz::v1beta1::{GenericAuthorization, MsgGrant, MsgGrantResponse},
bank::v1beta1::MsgSend,
};
use cosmwasm_std::coins;
use cw_orch_core::environment::{BankQuerier, TxHandler};
use cw_orch_daemon::Daemon;
use cw_orch_networks::networks::LOCAL_JUNO;
use cw_orch_traits::Stargate;
use prost::Message;
use prost::Name;
use prost_types::{Any, Timestamp};

pub const SECOND_MNEMONIC: &str ="salute trigger antenna west ignore own dance bounce battle soul girl scan test enroll luggage sorry distance traffic brand keen rich syrup wood repair";

#[test]
#[serial_test::serial]
fn authz() -> anyhow::Result<()> {
use cw_orch_networks::networks;

let runtime = tokio::runtime::Runtime::new().unwrap();

let daemon = Daemon::builder()
.chain(networks::LOCAL_JUNO)
.handle(runtime.handle())
.build()
.unwrap();

let sender = daemon.sender().to_string();

let second_daemon = Daemon::builder()
.chain(networks::LOCAL_JUNO)
.handle(runtime.handle())
.with_authz(sender.clone())
.mnemonic(SECOND_MNEMONIC)
.build()
.unwrap();

let grantee = second_daemon.sender().to_string();

let current_timestamp = daemon.block_info()?.time;

// We start by granting authz to an account
daemon.commit_any::<MsgGrantResponse>(
vec![Any {
type_url: "/cosmos.authz.v1beta1.MsgGrant".to_string(),
value: MsgGrant {
granter: sender.clone(),
grantee: grantee.clone(),
grant: Some(cosmrs::proto::cosmos::authz::v1beta1::Grant {
authorization: Some(cosmrs::Any {
type_url: "/cosmos.authz.v1beta1.GenericAuthorization".to_string(),
value: GenericAuthorization {
msg: MsgSend::type_url(),
}
.encode_to_vec(),
}),
expiration: Some(Timestamp {
seconds: (current_timestamp.seconds() + 3600) as i64,
nanos: 0,
}),
}),
}
.encode_to_vec(),
}],
None,
)?;

// The we send some funds to the account
runtime.block_on(
daemon
.daemon
.sender
.bank_send(&grantee, coins(1_000_000, LOCAL_JUNO.gas_denom)),
)?;

// And send a large amount of tokens on their behalf
runtime.block_on(
second_daemon
.daemon
.sender
.bank_send(&grantee, coins(5_000_000, LOCAL_JUNO.gas_denom)),
)?;

// the balance of the grantee whould be 6_000_000 or close

let grantee_balance =
daemon.balance(grantee.clone(), Some(LOCAL_JUNO.gas_denom.to_string()))?;

assert_eq!(grantee_balance.first().unwrap().amount.u128(), 6_000_000);

Ok(())
}
}
Loading
Loading