Skip to content

Commit

Permalink
feat(x/wasm): add AllKeys query binding (#185)
Browse files Browse the repository at this point in the history
* feat(cosmwasm): add support for calling warden module from contracts

* feat(cosmwasm): add bindings and sample contract

* fix(cosmwasm): straightforward changes after the code review

* fix(cosmwasm): update changelog

* feat(cosmwasm): query keys from contracts

* fix(cosmwasm): update changelog

* feat(cosmwasm): populate contract related readme files

* fix(cosmwasm): update changelog file

* fix(cosmwasm): fix typos in readme files

* fix(cosmwasm): fix typos

* fix(cosmwasm): sync rust types with updated proto definitions

* fix(cosmwasm) rewrite the sentence about the key to make it clearer

---------

Co-authored-by: Pavel Afanasyev <pavel.afanasyev@equilibrium.io>
  • Loading branch information
r0t0r-r0t0r and Pavel Afanasyev authored Apr 18, 2024
1 parent a9dd252 commit c96080d
Show file tree
Hide file tree
Showing 17 changed files with 327 additions and 109 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* (x/warden) [#160](https://github.com/warden-protocol/wardenprotocol/pull/160) Add Osmosis support
* Derive Osmosis addresses from ECDSA_SECP256K1 keys
* Extract DataForSigning for Osmosis Amino JSON transactions
* (cosmwasm) [#171](https://github.com/warden-protocol/wardenprotocol/pull/171) Add support for calling warden module from contracts
* (cosmwasm) [#171](https://github.com/warden-protocol/wardenprotocol/pull/171) Add support for executing NewKeyRequest from contracts
* (cosmwasm) [#185](https://github.com/warden-protocol/wardenprotocol/pull/185) Add support for querying AllKeys from contracts

### Bug Fixes

Expand All @@ -80,6 +81,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* (ci) [#137](https://github.com/warden-protocol/wardenprotocol/pull/137) Add CodeRabbit configuration file, copied from Cosmos SDK's repo
* (perf) [#138](https://github.com/warden-protocol/wardenprotocol/pull/138) Add benchmarks for most hit queries in `x/warden` and `x/intent` (ActionsByAddress, AllKeys, KeysBySpaceId)
* (chore) [#180](https://github.com/warden-protocol/wardenprotocol/pull/180) Update to use pnpm v9.0.0
* (docs) [#185](https://github.com/warden-protocol/wardenprotocol/pull/185) Add CosmWasm integration related docs.

## [v0.2.0](https://github.com/warden-protocol/wardenprotocol/releases/tag/v0.2.0) - 2024-03-26

Expand Down
83 changes: 82 additions & 1 deletion contracts/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
# Warden Contracts

This repo contains bindings (with usage examples) for accessing functionality of Warden Protocol blockchain
This repo contains bindings (with usage examples) for accessing core functionality of Warden Protocol blockchain
from CosmWasm contracts.

## Prerequisites

- You need rust to generate schema files.
- You need a Docker to build a contract.
- You need an account in the Warden Protocol blockchain with some balance in order to deploy contracts and perform transactions on it.

## Generate Schema

To generate schema files perform following commands:

```shell
# generate bindings schema
cd packages/bindings
cargo build
cargo run schema

cd ../..

# generate sample contract schema
cd contracts
cargo build
cargo run schema
```

## Build

```shell
Expand All @@ -11,3 +35,60 @@ docker run --rm -v "$(pwd)":/code \
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
cosmwasm/workspace-optimizer:0.13.0
```

After a successful build you'll see a newly generated `sample.wasm` file in the `artifacts` directory.

## Deploy a Contract

We assume that you have a `wardend` executable's directory in your `$PATH` environment variable in order to perform following steps.

All of the following commands are executed with the `alice` key from the default `--keyring-backend`, which is `os`.

```shell
wardend tx wasm store artifacts/sample.wasm --from alice -y --chain-id warden --gas 2000000
```

Now you should find the id that the system assigned to your code.
One of the methods to do this is to list all stored code bundles and find the last one.

```shell
wardend query wasm list-code
```

Let's assume its 100. Next step is to instantiate our contract using previously deployed code:

```shell
wardend tx wasm instantiate 100 '{}' --from alice --label "Group 1" --no-admin -y --chain-id warden
```

Let's find out address of the newly created contract. The simple way to do it is to query all contracts
with code id that we used previously, and find the last one:

```shell
wardend query wasm list-contract-by-code 100
```

Let's assume its address is `warden1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqtn83hn`
and store it to the `$contract` environment variable for the convenience:

```shell
contract=warden1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqtn83hn
```

Now we are ready to interact with our contract!

## Interacting with Contract

You can query its state, for example, let's list all existing keys:

```shell
wardend query wasm contract-state smart $contract '{ "warden_all_keys": {"pagination":{"limit":0,"reverse":false}, "derive_addresses":[]} }'--chain-id warden
```

And perform transactions, let's create request for a new key:

```shell
wardend tx wasm execute $contract '{ "new_key_request": { "space_id": 1, "keychain_id": 2, "key_type": 1, "btl": 888, "intent_id": 0 } }' --from alice -y
```

Note that `space_id` 1 and `keychain_id` 2 should already exist before your transaction.
7 changes: 7 additions & 0 deletions contracts/contracts/sample/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
# Sample

This is a sample contract which uses bindings for the core Warden Protocol blockchain functionality.

You can deploy it by itself, or you can use it as a starting point for your own contract.

Note that this is a preview, so only limited functionality available right now.
The sample contract exposes `NewKeyRequest` transaction and `AllKeys` query, but more are on the way!
3 changes: 2 additions & 1 deletion contracts/contracts/sample/src/bin/schema.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use cosmwasm_schema::write_api;

use sample::msg::{ExecuteMsg};
use sample::msg::{ExecuteMsg, QueryMsg};

fn main() {
write_api! {
execute: ExecuteMsg,
query: QueryMsg
}
}
37 changes: 23 additions & 14 deletions contracts/contracts/sample/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
use cosmwasm_std::{
Addr, Api, DepsMut, Empty, Env, MessageInfo, Response,
StdResult,
};
use cosmwasm_std::{Binary, Deps, DepsMut, Empty, Env, MessageInfo, PageRequest, Response, StdResult, to_json_binary};
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cw2::set_contract_version;

use bindings::msg::{KeyType, WardenMsg};
use bindings::WardenProtocolMsg;
use bindings::{WardenProtocolMsg, WardenProtocolQuery, QueryKeysResponse};
use bindings::msg::{WardenMsg};
use bindings::key::{KeyType};
use bindings::querier::WardenQuerier;
use bindings::query::AddressType;

use crate::error::ContractError;
use crate::msg::ExecuteMsg;
use crate::msg::{ExecuteMsg, QueryMsg};

// version info for migration info
const CONTRACT_NAME: &str = "crates.io:wardenprotocol-sample";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
deps: DepsMut,
deps: DepsMut<WardenProtocolQuery>,
_env: Env,
_info: MessageInfo,
_msg: Empty,
Expand All @@ -27,13 +27,9 @@ pub fn instantiate(
Ok(Response::default())
}

pub fn map_validate(api: &dyn Api, admins: &[String]) -> StdResult<Vec<Addr>> {
admins.iter().map(|addr| api.addr_validate(addr)).collect()
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
deps: DepsMut,
deps: DepsMut<WardenProtocolQuery>,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
Expand All @@ -44,7 +40,7 @@ pub fn execute(
}

fn execute_new_key_request(
_deps: DepsMut,
_deps: DepsMut<WardenProtocolQuery>,
_env: Env,
_info: MessageInfo,
space_id: u64,
Expand All @@ -65,3 +61,16 @@ fn execute_new_key_request(
.add_attribute("action", "new_key_request");
Ok(res)
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps<WardenProtocolQuery>, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
QueryMsg::WardenAllKeys { pagination, derive_addresses } => to_json_binary(&query_warden_all_keys(deps, pagination, derive_addresses)?)
}
}

pub fn query_warden_all_keys(deps: Deps<WardenProtocolQuery>, pagination: PageRequest, derive_addresses: Vec<AddressType>) -> StdResult<QueryKeysResponse> {
let querier = WardenQuerier::new(&deps.querier);
let response = querier.query_warden_all_keys(pagination, derive_addresses)?;
Ok(response)
}
14 changes: 12 additions & 2 deletions contracts/contracts/sample/src/msg.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use cosmwasm_schema::{cw_serde};
use bindings::msg::KeyType;
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::PageRequest;
use bindings::key::KeyType;
use bindings::query::{AddressType};

#[cw_serde]
pub enum ExecuteMsg
Expand All @@ -12,3 +14,11 @@ pub enum ExecuteMsg
intent_id: u64,
},
}

#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg
{
#[returns(bindings::QueryKeysResponse)]
WardenAllKeys { pagination: PageRequest, derive_addresses: Vec<AddressType> }
}
8 changes: 8 additions & 0 deletions contracts/packages/bindings/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
# Bindings

This crate provides bindings for the Warden Protocol blockchain core functionality.
You can use it in your own contracts to interact with a Warden Protocol.

Note that this is a preview, so only limited functionality available right now.
You can execute `NewKeyRequest` and query `AllKeys`, but more on the way!

To start using Warden Protocol from the CosmWasm contracts, please refer to the sample contract.
12 changes: 11 additions & 1 deletion contracts/packages/bindings/src/bin/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fs::create_dir_all;

use cosmwasm_schema::{export_schema_with_title, remove_schemas, schema_for};

use bindings::WardenProtocolMsg;
use bindings::{WardenProtocolMsg, WardenProtocolQuery, QueryKeysResponse};

fn main() {
let mut out_dir = current_dir().unwrap();
Expand All @@ -16,4 +16,14 @@ fn main() {
&out_dir,
"WardenProtocolMsg",
);
export_schema_with_title(
&schema_for!(WardenProtocolQuery),
&out_dir,
"WardenProtocolQuery",
);
export_schema_with_title(
&schema_for!(QueryKeysResponse),
&out_dir,
"QueryKeysResponse",
);
}
15 changes: 15 additions & 0 deletions contracts/packages/bindings/src/key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Binary};

pub type KeyType = i32;

#[cw_serde]
pub struct Key {
id: u64,
space_id: u64,
keychain_id: u64,
#[serde(rename = "type")]
key_type: KeyType,
public_key: Binary,
intent_id: u64,
}
5 changes: 5 additions & 0 deletions contracts/packages/bindings/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
pub mod msg;
pub mod query;
pub mod querier;
pub mod key;

pub use crate::msg::WardenProtocolMsg;
pub use crate::query::{WardenProtocolQuery, QueryKeysResponse};
pub use crate::querier::WardenQuerier;
16 changes: 2 additions & 14 deletions contracts/packages/bindings/src/msg.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{CustomMsg};
use cosmwasm_std::CosmosMsg;
use cosmwasm_std::{CosmosMsg, CustomMsg};
use crate::key::KeyType;

/// WardenMsg is an override of CosmosMsg::Custom to add support for Warden Protocol's custom message types
#[cw_serde]
Expand All @@ -10,18 +10,6 @@ pub enum WardenProtocolMsg {

impl CustomMsg for WardenProtocolMsg {}

#[cw_serde]
pub enum KeyType {
/// The key type is missing.
Unspecified,

/// The key is an ECDSA secp256k1 key.
EcdsaSecp256k1,

/// The key is an EdDSA Ed25519 key.
EddsaEd25519,
}

/// WardenMsg captures all possible messages we can return to Warden Protocol's native warden module
#[cw_serde]
pub enum WardenMsg {
Expand Down
20 changes: 20 additions & 0 deletions contracts/packages/bindings/src/querier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use cosmwasm_std::{PageRequest, QuerierWrapper, StdResult};

use crate::{QueryKeysResponse, WardenProtocolQuery};
use crate::query::{AddressType, WardenQuery};

pub struct WardenQuerier<'a> {
querier: &'a QuerierWrapper<'a, WardenProtocolQuery>,
}

impl<'a> WardenQuerier<'a> {
pub fn new(querier: &'a QuerierWrapper<WardenProtocolQuery>) -> Self {
WardenQuerier { querier }
}

pub fn query_warden_all_keys(&self, pagination: PageRequest, derive_addresses: Vec<AddressType>) -> StdResult<QueryKeysResponse> {
let request = WardenProtocolQuery::Warden(WardenQuery::AllKeys { pagination, derive_addresses });
let response = self.querier.query::<QueryKeysResponse>(&request.into())?;
Ok(response)
}
}
42 changes: 42 additions & 0 deletions contracts/packages/bindings/src/query.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{CustomQuery, Addr, PageRequest};
use cosmwasm_std::{Binary};
use crate::key::Key;

#[cw_serde]
pub enum WardenProtocolQuery {
Warden(WardenQuery),
}

impl CustomQuery for WardenProtocolQuery {}

#[cw_serde]
pub enum WardenQuery {
AllKeys { pagination: PageRequest, derive_addresses: Vec<AddressType> },
}

pub type AddressType = i32;

#[cw_serde]
pub struct PageResponse {
next_key: Option<Binary>,
total: Option<u64>,
}

#[cw_serde]
pub struct AddressResponse {
address: Addr,
#[serde(rename = "type")]
address_type: AddressType
}

#[cw_serde]
pub struct QueryKeyResponse {
key: Key,
addresses: Vec<AddressResponse>
}
#[cw_serde]
pub struct QueryKeysResponse {
pagination: PageResponse,
keys: Option<QueryKeyResponse>,
}
Loading

0 comments on commit c96080d

Please sign in to comment.