Skip to content
This repository has been archived by the owner on Dec 21, 2022. It is now read-only.

Commit

Permalink
feat(orchestrate): introduce cw-orchestrate
Browse files Browse the repository at this point in the history
* Add `cw-orchestrate` to the repo.

* Format `toml` files using `taplo`.

Signed-off-by: aeryz <[email protected]>
  • Loading branch information
aeryz committed Nov 21, 2022
1 parent b4896e0 commit 35b605b
Show file tree
Hide file tree
Showing 15 changed files with 2,430 additions and 46 deletions.
1,027 changes: 999 additions & 28 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[workspace]
members = [ "vm", "vm-wasmi" ]
members = ["vm", "vm-wasmi", "orchestrate"]
resolver = "2"
33 changes: 33 additions & 0 deletions orchestrate/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[package]
name = "cw-orchestrate"
version = "0.1.0"
edition = "2021"

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

[dependencies]
cosmwasm-vm = { path = "../vm" }
cosmwasm-vm-wasmi = { path = "../vm-wasmi" }
cosmwasm-std = { git = "https://github.com/ComposableFi/cosmwasm", rev = "21351cc1ced863b9af7c8a69f923036bc919b3b1", features = [
"stargate",
"ibc3",
] }
serde_json = "1.0"
serde = { version = "1.0", default-features = false, features = [
"alloc",
"derive",
] }
wasmi = { git = "https://github.com/ComposableFi/wasmi", rev = "cd8c0c775a1d197a35ff3d5c7d6cded3d476411b", default-features = false }
wasm-instrument = { version = "0.2", default-features = false }
log = { version = "0.4", default-features = false }
cosmwasm-crypto = { git = "https://github.com/ComposableFi/cosmwasm" }
sha2 = { version = "0.10", default-features = false }
cw20-ics20-contract = { package = "cw20-ics20", git = "https://github.com/CosmWasm/cw-plus", rev = "53dc88fdb81888cbd3dae8742e7318b35d3d0c0f", default-features = false, features = [
"library",
] }
reqwest = { version = "0.11", features = ["blocking"] }
base64 = "0.13.1"

[dev-dependencies]
cw20 = "0.16"
cw20-base = { version = "0.16", features = ["library"] }
86 changes: 86 additions & 0 deletions orchestrate/examples/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#![feature(assert_matches)]

#[cfg(test)]
mod tests {
use cosmwasm_std::to_binary;
use cosmwasm_vm::executor::{
CosmwasmExecutionResult, CosmwasmQueryResult, InstantiateResult, QueryResult,
};
use cw20::{BalanceResponse, Cw20Coin};
use cw20_base::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
use cw_orchestrate::{
execute,
fetcher::*,
instantiate, query,
vm::{Account, State},
};
use std::assert_matches::assert_matches;

const CW20_BASE_URL: &'static str =
"https://github.com/CosmWasm/cw-plus/releases/download/v0.16.0/cw20_base.wasm";

#[test]
fn works() {
let code = CosmosFetcher::from_contract_addr(
"https://juno-api.polkachu.com",
"juno19rqljkh95gh40s7qdx40ksx3zq5tm4qsmsrdz9smw668x9zdr3lqtg33mf",
)
.unwrap();
let sender = Account::unchecked("sender");

let mut state = State::with_codes(vec![&code]);
let (contract, res) = instantiate(
&mut state,
&sender,
1,
None,
vec![],
100_000_000,
InstantiateMsg {
name: "Picasso".into(),
symbol: "PICA".into(),
decimals: 12,
initial_balances: vec![Cw20Coin {
amount: 10000000_u128.into(),
address: sender.0.clone().into_string(),
}],
mint: None,
marketing: None,
},
)
.unwrap();
assert_matches!(res, InstantiateResult(CosmwasmExecutionResult::Ok(_)));

let _ = execute(
&mut state,
&sender,
&contract,
vec![],
100_000_000,
ExecuteMsg::Transfer {
recipient: "receiver".into(),
amount: 10_000_u128.into(),
},
)
.unwrap();

assert_eq!(
query(
&mut state,
&contract,
QueryMsg::Balance {
address: "receiver".into()
}
)
.unwrap(),
QueryResult(CosmwasmQueryResult::Ok(
to_binary(&BalanceResponse {
balance: 10_000_u128.into()
})
.unwrap()
))
);
}
}

fn main() {}
153 changes: 153 additions & 0 deletions orchestrate/src/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
use crate::vm::{create_vm, Account, Context, Gas, State, VmError};
use cosmwasm_std::{Addr, BlockInfo, Coin, ContractInfo, Empty, Env, MessageInfo, Timestamp};
use cosmwasm_vm::{
executor::{
cosmwasm_call, ExecuteInput, ExecuteResult, InstantiateInput, InstantiateResult,
QueryInput, QueryResult,
},
system::{CosmwasmCodeId, CosmwasmContractMeta},
};
use cosmwasm_vm_wasmi::WasmiVM;
use serde::Serialize;

pub fn instantiate_raw(
vm_state: &mut State,
sender: &Account,
code_id: CosmwasmCodeId,
admin: Option<Account>,
funds: Vec<Coin>,
gas: u64,
message: &[u8],
) -> Result<(Account, InstantiateResult<Empty>), VmError> {
let code_hash = &vm_state
.codes
.get(&code_id)
.ok_or(VmError::CodeNotFound(code_id))?
.1;
let contract_addr = Account::generate(code_hash, message);
vm_state.gas = Gas::new(gas);
if vm_state.contracts.contains_key(&contract_addr) {
return Err(VmError::AlreadyInstantiated);
}
vm_state.contracts.insert(
contract_addr.clone(),
CosmwasmContractMeta {
code_id,
admin,
label: String::from("test-label"),
},
);
let mut vm = create_vm(
vm_state,
Env {
block: BlockInfo {
height: 0xDEADC0DE,
time: Timestamp::from_seconds(10000),
chain_id: "abstract-test".into(),
},
transaction: None,
contract: ContractInfo {
address: contract_addr.clone().into(),
},
},
MessageInfo {
sender: sender.clone().into(),
funds,
},
);

Ok((
contract_addr,
cosmwasm_call::<InstantiateInput<Empty>, WasmiVM<Context>>(&mut vm, message)?,
))
}

pub fn instantiate<M: Serialize>(
vm_state: &mut State,
sender: &Account,
code_id: CosmwasmCodeId,
admin: Option<Account>,
funds: Vec<Coin>,
gas: u64,
message: M,
) -> Result<(Account, InstantiateResult<Empty>), VmError> {
let message = serde_json::to_vec(&message).map_err(|_| VmError::CannotSerialize)?;
instantiate_raw(vm_state, sender, code_id, admin, funds, gas, &message)
}

pub fn execute_raw(
vm_state: &mut State,
sender: &Account,
contract: &Account,
funds: Vec<Coin>,
gas: u64,
message: &[u8],
) -> Result<ExecuteResult<Empty>, VmError> {
vm_state.gas = Gas::new(gas);
let mut vm = create_vm(
vm_state,
Env {
block: BlockInfo {
height: 0xCAFEBABE,
time: Timestamp::from_seconds(10000),
chain_id: "abstract-test".into(),
},
transaction: None,
contract: ContractInfo {
address: contract.clone().into(),
},
},
MessageInfo {
sender: sender.clone().into(),
funds,
},
);
cosmwasm_call::<ExecuteInput<Empty>, WasmiVM<Context>>(&mut vm, message)
}

pub fn execute<M: Serialize>(
vm_state: &mut State,
sender: &Account,
contract: &Account,
funds: Vec<Coin>,
gas: u64,
message: M,
) -> Result<ExecuteResult<Empty>, VmError> {
let message = serde_json::to_vec(&message).map_err(|_| VmError::CannotSerialize)?;
execute_raw(vm_state, sender, contract, funds, gas, &message)
}

pub fn query_raw(
vm_state: &mut State,
contract: &Account,
message: &[u8],
) -> Result<QueryResult, VmError> {
let mut vm = create_vm(
vm_state,
Env {
block: BlockInfo {
height: 0xCAFEBABE,
time: Timestamp::from_seconds(10000),
chain_id: "abstract-test".into(),
},
transaction: None,
contract: ContractInfo {
address: contract.clone().into(),
},
},
MessageInfo {
sender: Addr::unchecked("MOCK"),
funds: vec![],
},
);
cosmwasm_call::<QueryInput, WasmiVM<Context>>(&mut vm, message)
}

pub fn query<M: Serialize>(
vm_state: &mut State,
contract: &Account,
message: M,
) -> Result<QueryResult, VmError> {
let message = serde_json::to_vec(&message).map_err(|_| VmError::CannotSerialize)?;
query_raw(vm_state, contract, &message)
}
15 changes: 15 additions & 0 deletions orchestrate/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use core::fmt::Display;

#[derive(Debug)]
pub enum Error {
Network,
CannotDecode,
CannotSerialize,
CannotDeserialize,
}

impl Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self)
}
}
81 changes: 81 additions & 0 deletions orchestrate/src/fetcher.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use crate::error::Error;
use serde::{Deserialize, Serialize};

pub struct FileFetcher;

impl FileFetcher {
pub fn from_url<S: AsRef<str>>(url: S) -> Result<Vec<u8>, Error> {
Ok(reqwest::blocking::get(url.as_ref())
.map_err(|_| Error::Network)?
.bytes()
.map_err(|_| Error::Network)?
.to_vec())
}
}

pub trait CosmosApi {
const CONTRACT_ENDPOINT: &'static str;
const CODE_ENDPOINT: &'static str;

fn from_contract_addr<S: AsRef<str>>(
endpoint: S,
contract_address: S,
) -> Result<Vec<u8>, Error> {
let response = reqwest::blocking::get(&format!(
"{}/{}/{}",
endpoint.as_ref(),
Self::CONTRACT_ENDPOINT,
contract_address.as_ref()
))
.map_err(|_| Error::Network)?
.text()
.map_err(|_| Error::Network)?;

let response: ContractResponse =
serde_json::from_str(&response).map_err(|_| Error::CannotDeserialize)?;
let code_id: u64 = response
.contract_info
.code_id
.parse()
.map_err(|_| Error::CannotDeserialize)?;
Self::from_code_id(endpoint, code_id)
}

fn from_code_id<S: AsRef<str>>(endpoint: S, code_id: u64) -> Result<Vec<u8>, Error> {
let response = reqwest::blocking::get(&format!(
"{}/{}/{}",
endpoint.as_ref(),
Self::CODE_ENDPOINT,
code_id
))
.map_err(|_| Error::Network)?
.text()
.map_err(|_| Error::Network)?;

let response: CosmosResponse =
serde_json::from_str(&response).map_err(|_| Error::CannotDeserialize)?;
base64::decode(&response.data).map_err(|_| Error::CannotDecode)
}
}

pub struct CosmosFetcher;

impl CosmosApi for CosmosFetcher {
const CONTRACT_ENDPOINT: &'static str = "/cosmwasm/wasm/v1/contract";
const CODE_ENDPOINT: &'static str = "/cosmwasm/wasm/v1/code";
}

#[derive(Debug, Serialize, Deserialize)]
struct CodeInfo {
code_id: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct ContractResponse {
contract_info: CodeInfo,
}

#[derive(Debug, Serialize, Deserialize)]
struct CosmosResponse {
data: String,
}
12 changes: 12 additions & 0 deletions orchestrate/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#![feature(generic_associated_types)]
#![feature(trait_alias)]
#![cfg_attr(feature = "no_std", no_std)]

extern crate alloc;

mod api;
pub mod error;
pub mod fetcher;
pub mod vm;

pub use api::*;
Loading

0 comments on commit 35b605b

Please sign in to comment.