-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
442 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
[package] | ||
name = "scw" | ||
version = "0.1.0" | ||
authors = ["bataotaku"] | ||
edition = "2021" | ||
|
||
exclude = [ | ||
# Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. | ||
"contract.wasm", | ||
"hash.txt", | ||
] | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[lib] | ||
crate-type = ["cdylib", "rlib"] | ||
|
||
[profile.release] | ||
opt-level = 3 | ||
debug = false | ||
rpath = false | ||
lto = true | ||
debug-assertions = false | ||
codegen-units = 1 | ||
panic = 'abort' | ||
incremental = false | ||
overflow-checks = true | ||
|
||
[features] | ||
# for more explicit tests, cargo test --features=backtraces | ||
backtraces = ["cosmwasm-std/backtraces"] | ||
# use library feature to disable all instantiate/execute/query exports | ||
library = [] | ||
|
||
[package.metadata.scripts] | ||
optimize = """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 \ | ||
cosmwasm/rust-optimizer:0.12.10 | ||
""" | ||
|
||
[dependencies] | ||
cosmwasm-schema = "1.1.3" | ||
cosmwasm-std = "1.1.3" | ||
cosmwasm-storage = "1.3.2" | ||
cw-storage-plus = "1.0.1" | ||
cw2 = "1.0.1" | ||
osmosis-std = "0.16.1" | ||
schemars = "0.8.10" | ||
prost = {version = "0.11.2", default-features = false, features = ["prost-derive"]} | ||
serde = { version = "1.0.145", default-features = false, features = ["derive"] } | ||
thiserror = { version = "1.0.31" } | ||
sha2 = "0.10" | ||
|
||
[dev-dependencies] | ||
cw-multi-test = "0.16.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
use cosmwasm_schema::write_api; | ||
|
||
use entrypoint::msg::{ExecuteMsg, InstantiateMsg}; | ||
|
||
fn main() { | ||
write_api! { | ||
instantiate: InstantiateMsg, | ||
execute: ExecuteMsg, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
#[cfg(not(feature = "library"))] | ||
use cosmwasm_std::entry_point; | ||
use cosmwasm_std::{ | ||
to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult, Uint64, | ||
}; | ||
use cw2::set_contract_version; | ||
|
||
use crate::error::ContractError; | ||
use crate::msg::{ExecuteMsg, InstantiateMsg, BatchUserOp}; | ||
use crate::state::USER_NONCE; | ||
use sha2::{Digest, Sha256}; | ||
|
||
// version info for migration info | ||
const CONTRACT_NAME: &str = "crates.io:wise-wallet"; | ||
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); | ||
|
||
#[cfg_attr(not(feature = "library"), entry_point)] | ||
pub fn instantiate( | ||
deps: DepsMut, | ||
_env: Env, | ||
info: MessageInfo, | ||
msg: InstantiateMsg, | ||
) -> Result<Response, ContractError> { | ||
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; | ||
Ok(Response::new() | ||
.add_attribute("method", "instantiate") | ||
.add_attribute("owner", info.sender)) | ||
} | ||
|
||
#[cfg_attr(not(feature = "library"), entry_point)] | ||
pub fn execute( | ||
deps: DepsMut, | ||
_env: Env, | ||
info: MessageInfo, | ||
msg: ExecuteMsg, | ||
) -> Result<Response, ContractError> { | ||
match msg { | ||
ExecuteMsg::HandleUserOps { UserOps } => execute::handle_batch_user_op(deps, UserOps), | ||
} | ||
} | ||
|
||
pub mod execute { | ||
use std::vec; | ||
|
||
use cosmwasm_std::CosmosMsg; | ||
use crate::msg::BatchUserOp; | ||
|
||
use super::*; | ||
pub fn handle_batch_user_op( | ||
deps: DepsMut, | ||
batch_op: BatchUserOp, | ||
) -> Result<Response, ContractError> { | ||
let mut msgs: Vec<CosmosMsg> = Vec::new(); | ||
|
||
// Check the nonce once for the entire batch | ||
let usernonce = USER_NONCE | ||
.load(deps.storage, batch_op.Sender) | ||
.unwrap_or_default(); | ||
if usernonce + 1 != batch_op.Nonce.u128() { | ||
return Err(ContractError::InvalidNonce { | ||
user: batch_op.Sender.to_string(), | ||
}); | ||
} | ||
|
||
// Construct a piece of data representing the entire batch to verify the signature | ||
let mut all_bin_msgs = Vec::new(); | ||
for op in &batch_op.Ops { | ||
let msg: CosmosMsg<_> = CosmosMsg::Wasm(cosmwasm_std::WasmMsg::Execute { | ||
contract_addr: op.To.into_string(), | ||
msg: op.Calldata.clone(), | ||
funds: op.funds.clone(), | ||
}); | ||
all_bin_msgs.push(to_binary(&msg)?); | ||
msgs.push(msg); | ||
} | ||
|
||
let combined_data: Vec<u8> = all_bin_msgs.into_iter().flat_map(|b| b.0).collect(); | ||
let hash = sha256(&combined_data); | ||
let sig = batch_op.Signature.clone().unwrap(); | ||
|
||
if !deps | ||
.api | ||
.secp256k1_verify(&hash, &sig, &batch_op.Pubkey) | ||
.unwrap_or_default() | ||
{ | ||
return Err(ContractError::Unauthorized {}); | ||
} | ||
|
||
Ok(Response::new().add_messages(msgs)) | ||
} | ||
|
||
} | ||
|
||
pub fn sha256(msg: &[u8]) -> Result<Vec<u8>, der::error::Error> { | ||
let mut hasher = Sha256::new(); | ||
hasher.update(msg); | ||
let result = hasher.finalize().to_vec(); | ||
Ok(result) | ||
} | ||
|
||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; | ||
use cosmwasm_std::{coins, from_binary, Addr, Uint128}; | ||
use crate::msg::SingleUserOp; | ||
|
||
#[test] | ||
fn test_handle_batch_user_op() { | ||
let mut deps = mock_dependencies(); | ||
let env = mock_env(); | ||
let sender = "sender".to_string(); | ||
let info = mock_info(&sender, &coins(1000, "earth")); | ||
|
||
// Create a mock BatchUserOp | ||
let ops = BatchUserOp { | ||
Sender: Addr::unchecked(sender.clone()), | ||
Ops: vec![ | ||
SingleUserOp { | ||
To: Addr::unchecked("contract1"), | ||
Calldata: Binary::from(b"do something".to_vec()), | ||
funds: coins(500, "earth"), | ||
}, | ||
SingleUserOp { | ||
To: Addr::unchecked("contract2"), | ||
Calldata: Binary::from(b"do something else".to_vec()), | ||
funds: coins(300, "earth"), | ||
}, | ||
], | ||
Nonce: Uint128::from(1u64), | ||
Signature: Some(Binary::from(b"fake_signature".to_vec())), | ||
Pubkey: Binary::from(b"fake_pubkey".to_vec()), | ||
}; | ||
|
||
let execute_msg = ExecuteMsg::HandleUserOps { UserOps: ops }; | ||
|
||
// Call the execute function | ||
let result = execute(deps.as_mut(), env.clone(), info.clone(), execute_msg); | ||
|
||
// Assert Unauthorized error due to fake signature | ||
assert_eq!( | ||
result.unwrap_err(), | ||
ContractError::Unauthorized {} | ||
); | ||
|
||
// Additional assertions can be added as required based on the logic | ||
// For example, you can store and query data similar to the provided test, | ||
// and check the expected results. | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
use cosmwasm_std::StdError; | ||
use thiserror::Error; | ||
|
||
#[derive(Error, Debug)] | ||
pub enum ContractError { | ||
#[error("{0}")] | ||
Std(#[from] StdError), | ||
|
||
#[error("Unauthorized")] | ||
Unauthorized {}, | ||
|
||
#[error("Invalid Nonce for user {user}")] | ||
InvalidNonce { user: String }, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pub mod contract; | ||
mod error; | ||
pub mod msg; | ||
pub mod state; | ||
pub use crate::error::ContractError; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
use cosmwasm_schema::{cw_serde, QueryResponses}; | ||
use cosmwasm_std::{Addr, Binary, Uint128, Uint64, Coin}; | ||
|
||
#[cw_serde] | ||
pub struct InstantiateMsg {} | ||
|
||
#[cw_serde] | ||
pub enum ExecuteMsg { | ||
HandleUserOps { UserOps: BatchUserOp }, | ||
} | ||
|
||
#[cw_serde] | ||
pub struct SingleUserOp { | ||
pub To: Addr, | ||
pub Calldata: Binary, | ||
pub funds: Vec<Coin>, | ||
} | ||
|
||
#[cw_serde] | ||
pub struct BatchUserOp { | ||
pub Sender: Addr, | ||
pub Ops: Vec<SingleUserOp>, | ||
pub Nonce: Uint128, | ||
pub Signature: Option<Binary>, | ||
pub Pubkey: Binary, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
use schemars::JsonSchema; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use cosmwasm_std::Addr; | ||
use cw_storage_plus::{Item, Map}; | ||
|
||
pub const USER_NONCE: Map<Addr, u128> = Map::new("USER_NONCE"); |
Oops, something went wrong.