diff --git a/contracts/reclaim_user_map/Cargo.toml b/contracts/reclaim_user_map/Cargo.toml new file mode 100644 index 0000000..7e4211e --- /dev/null +++ b/contracts/reclaim_user_map/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "reclaim-user-map" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +# enable feature if you want to disable entry points +library = [] + +[dependencies] +cosmwasm-schema = "1.3.1" +cosmwasm-std = "1.3.1" +cw-storage-plus = "1.1.0" +thiserror = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +getrandom = { workspace = true } +reclaim_xion = { package = "reclaim-xion", git = "https://github.com/burnt-labs/xion-sdk-onchain-integration.git", features = ["library"], rev = "5c67c33d0575c2ede6d2512c5d724b52019974bb"} \ No newline at end of file diff --git a/contracts/reclaim_user_map/examples/schema.rs b/contracts/reclaim_user_map/examples/schema.rs new file mode 100644 index 0000000..bc318a0 --- /dev/null +++ b/contracts/reclaim_user_map/examples/schema.rs @@ -0,0 +1,11 @@ +use cosmwasm_schema::write_api; +use reclaim_user_map::msg::*; + +fn main() { + write_api! { + instantiate: InstantiateMsg, + query: QueryMsg, + execute: ExecuteMsg, + migrate: MigrateMsg, + }; +} diff --git a/contracts/reclaim_user_map/src/contract.rs b/contracts/reclaim_user_map/src/contract.rs new file mode 100644 index 0000000..c283aa7 --- /dev/null +++ b/contracts/reclaim_user_map/src/contract.rs @@ -0,0 +1,84 @@ +use std::collections::HashMap; +use crate::error::ContractError; +use crate::error::ContractResult; +use crate::msg::InstantiateMsg; +use crate::msg::{ExecuteMsg, QueryMsg}; +use crate::state::{CLAIM_VALUE_KEY, USER_MAP, VERIFICATION_ADDR}; +use cosmwasm_std::{entry_point, to_json_binary, Addr, Binary, CosmosMsg, Deps, DepsMut, Env, MessageInfo, Order, Response, StdResult, WasmMsg}; +use serde_json::Value; +use crate::error::ContractError::ClaimKeyInvalid; + +#[entry_point] +pub fn instantiate( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: InstantiateMsg, +) -> Result { + deps.api.addr_validate(msg.verification_addr.as_str())?; + VERIFICATION_ADDR.save(deps.storage, &msg.verification_addr)?; + if msg.claim_key.is_empty() { + return Err(ClaimKeyInvalid) + } + CLAIM_VALUE_KEY.save(deps.storage, &msg.claim_key)?; + + Ok(Response::new() + .add_attribute("method", "instantiate") + .add_attribute("owner", info.sender)) +} +#[entry_point] +pub fn execute( + deps: DepsMut, + _: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> ContractResult { + match msg { + ExecuteMsg::Update { value } => { + // validate JSON + let context: HashMap<&str, Value> = serde_json::from_str(&value.proof.claimInfo.context)?; + + let extracted_parameters = match context.get("extractedParameters") { + None => return Err(ContractError::ExtractedParametersMissing {}), + Some(v) => v + }; + + let verified_value = match extracted_parameters.get(CLAIM_VALUE_KEY.load(deps.storage)?.as_str()) { + Some(v) => v.to_string(), + None => return Err(ContractError::JSONKeyMissing {}), + }; + + USER_MAP.save(deps.storage, info.sender, &verified_value)?; + Ok(Response::default().add_message(CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: VERIFICATION_ADDR.load(deps.storage)?.into_string(), + msg: to_json_binary(&reclaim_xion::msg::ExecuteMsg::VerifyProof(value))?, + funds: vec![], + }))) + } + } +} + +#[entry_point] +pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + match msg { + QueryMsg::GetValueByUser { address } => { + let value = USER_MAP.load(deps.storage, address)?; + to_json_binary(&value) + } + QueryMsg::GetUsers {} => { + let mut addrs: Vec = Vec::new(); + for addr in USER_MAP.keys(deps.storage, None, None, Order::Ascending) { + addrs.push(addr?) + } + to_json_binary(&addrs) + } + QueryMsg::GetMap {} => { + let mut response: Vec<(Addr, String)> = Vec::new(); + for item in USER_MAP.range(deps.storage, None, None, Order::Ascending) { + let (key, value) = item?; + response.push((key, value)) + } + to_json_binary(&response) + } + } +} diff --git a/contracts/reclaim_user_map/src/error.rs b/contracts/reclaim_user_map/src/error.rs new file mode 100644 index 0000000..7ebab50 --- /dev/null +++ b/contracts/reclaim_user_map/src/error.rs @@ -0,0 +1,19 @@ +#[derive(Debug, thiserror::Error)] +pub enum ContractError { + #[error(transparent)] + Std(#[from] cosmwasm_std::StdError), + + #[error(transparent)] + JsonError(#[from] serde_json::Error), + + #[error("json key missing")] + JSONKeyMissing, + + #[error("extracted paramters missing")] + ExtractedParametersMissing, + + #[error("claim key invalid")] + ClaimKeyInvalid, +} + +pub type ContractResult = Result; diff --git a/contracts/reclaim_user_map/src/lib.rs b/contracts/reclaim_user_map/src/lib.rs new file mode 100644 index 0000000..dd94e38 --- /dev/null +++ b/contracts/reclaim_user_map/src/lib.rs @@ -0,0 +1,18 @@ +extern crate core; + +#[cfg(not(feature = "library"))] +pub mod contract; +mod error; +pub mod msg; +mod state; + +// the random function must be disabled in cosmwasm +use core::num::NonZeroU32; +use getrandom::Error; + +pub fn always_fail(_buf: &mut [u8]) -> Result<(), Error> { + let code = NonZeroU32::new(Error::CUSTOM_START).unwrap(); + Err(Error::from(code)) +} +use getrandom::register_custom_getrandom; +register_custom_getrandom!(always_fail); diff --git a/contracts/reclaim_user_map/src/msg.rs b/contracts/reclaim_user_map/src/msg.rs new file mode 100644 index 0000000..5e97aee --- /dev/null +++ b/contracts/reclaim_user_map/src/msg.rs @@ -0,0 +1,28 @@ +use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::Addr; +use reclaim_xion::msg::ProofMsg; + +#[cw_serde] +pub struct InstantiateMsg { + pub verification_addr: Addr, + pub claim_key: String, +} + +#[cw_serde] +pub enum ExecuteMsg { + Update { value: ProofMsg }, +} + +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg { + #[returns(Vec)] + GetUsers {}, + #[returns(String)] + GetValueByUser { address: Addr }, + #[returns(Vec<(Addr, String)>)] + GetMap {}, +} + +#[cw_serde] +pub struct MigrateMsg {} diff --git a/contracts/reclaim_user_map/src/state.rs b/contracts/reclaim_user_map/src/state.rs new file mode 100644 index 0000000..cefa0dc --- /dev/null +++ b/contracts/reclaim_user_map/src/state.rs @@ -0,0 +1,7 @@ +use cosmwasm_std::Addr; +use cw_storage_plus::{Item, Map}; + +pub const USER_MAP: Map = Map::new("user_map"); + +pub const VERIFICATION_ADDR: Item = Item::new("verification_addr"); +pub const CLAIM_VALUE_KEY: Item = Item::new("claim_value_key"); \ No newline at end of file