From 30320874b3f5173b8b765779cce0972423db3148 Mon Sep 17 00:00:00 2001 From: Valery Litvin Date: Tue, 7 Mar 2023 16:41:58 +0800 Subject: [PATCH 1/3] Updated gift release flow --- Cargo.lock | 24 +- Cargo.toml | 12 - contracts/cw-cyber-gift/Cargo.toml | 14 +- .../all_release_stage_state_response.json | 10 +- .../cw-cyber-gift/schema/execute_msg.json | 250 ----------------- contracts/cw-cyber-gift/schema/query_msg.json | 36 +-- .../schema/release_stage_state_response.json | 10 +- contracts/cw-cyber-gift/src/contract.rs | 12 +- contracts/cw-cyber-gift/src/execute.rs | 64 ++--- contracts/cw-cyber-gift/src/msg.rs | 11 +- contracts/cw-cyber-gift/src/query.rs | 22 +- contracts/cw-cyber-gift/src/state.rs | 4 +- contracts/cw-cyber-gift/src/tests.rs | 254 ++++++++++-------- contracts/cw-cyber-gift/test-data-20.csv | 21 ++ contracts/cw-cyber-passport/Cargo.toml | 11 - .../cw-cyber-passport/schema/execute_msg.json | 242 ----------------- contracts/cw-cyber-passport/src/execute.rs | 2 +- contracts/cw-cyber-subgraph/Cargo.toml | 11 - 18 files changed, 254 insertions(+), 756 deletions(-) create mode 100644 contracts/cw-cyber-gift/test-data-20.csv diff --git a/Cargo.lock b/Cargo.lock index 54dbbad..41ca577 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -274,6 +274,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "csv" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -289,11 +310,12 @@ dependencies = [ [[package]] name = "cw-cyber-gift" -version = "1.0.0" +version = "2.0.0" dependencies = [ "anyhow", "cosmwasm-schema", "cosmwasm-std", + "csv", "cw-cyber-passport", "cw-cyber-subgraph", "cw-multi-test", diff --git a/Cargo.toml b/Cargo.toml index 66ffce9..92e05b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,18 +1,6 @@ [workspace] members = ["contracts/*"] -[profile.release.package.cw-cyber-gift] -codegen-units = 1 -incremental = false - -[profile.release.package.cw-cyber-passport] -codegen-units = 1 -incremental = false - -[profile.release.package.cw-cyber-subgraph] -codegen-units = 1 -incremental = false - [profile.release] rpath = false lto = true diff --git a/contracts/cw-cyber-gift/Cargo.toml b/contracts/cw-cyber-gift/Cargo.toml index fc4a70e..be1d68f 100644 --- a/contracts/cw-cyber-gift/Cargo.toml +++ b/contracts/cw-cyber-gift/Cargo.toml @@ -1,23 +1,12 @@ [package] name = "cw-cyber-gift" -version = "1.0.0" +version = "2.0.0" authors = ["CyberHead"] edition = "2018" [lib] crate-type = ["cdylib", "rlib"] -[profile.release] -rpath = false -lto = true -overflow-checks = true -opt-level = 3 -debug = false -debug-assertions = false -codegen-units = 1 -incremental = false -panic = 'abort' - [features] # for more explicit tests, cargo test --features=backtraces backtraces = ["cosmwasm-std/backtraces"] @@ -44,6 +33,7 @@ sha2 = { version = "0.9.5", default-features = false } semver = "1" [dev-dependencies] +csv = "1.1" cosmwasm-schema = { version = "1.0.0" } cw-multi-test = { version = "0.13.4" } cw1-whitelist = { version = "0.13.4" } diff --git a/contracts/cw-cyber-gift/schema/all_release_stage_state_response.json b/contracts/cw-cyber-gift/schema/all_release_stage_state_response.json index 1d5cd47..d609aee 100644 --- a/contracts/cw-cyber-gift/schema/all_release_stage_state_response.json +++ b/contracts/cw-cyber-gift/schema/all_release_stage_state_response.json @@ -9,14 +9,10 @@ "releases": { "type": "array", "items": { - "$ref": "#/definitions/Uint64" + "type": "integer", + "format": "uint32", + "minimum": 0.0 } } - }, - "definitions": { - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } } } diff --git a/contracts/cw-cyber-gift/schema/execute_msg.json b/contracts/cw-cyber-gift/schema/execute_msg.json index feb7f3c..35cd6b0 100644 --- a/contracts/cw-cyber-gift/schema/execute_msg.json +++ b/contracts/cw-cyber-gift/schema/execute_msg.json @@ -290,43 +290,6 @@ }, "additionalProperties": false }, - { - "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", - "type": "object", - "required": [ - "stargate" - ], - "properties": { - "stargate": { - "type": "object", - "required": [ - "type_url", - "value" - ], - "properties": { - "type_url": { - "type": "string" - }, - "value": { - "$ref": "#/definitions/Binary" - } - } - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "ibc" - ], - "properties": { - "ibc": { - "$ref": "#/definitions/IbcMsg" - } - }, - "additionalProperties": false - }, { "type": "object", "required": [ @@ -338,18 +301,6 @@ } }, "additionalProperties": false - }, - { - "type": "object", - "required": [ - "gov" - ], - "properties": { - "gov": { - "$ref": "#/definitions/GovMsg" - } - }, - "additionalProperties": false } ] }, @@ -899,190 +850,6 @@ } ] }, - "GovMsg": { - "oneOf": [ - { - "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", - "type": "object", - "required": [ - "vote" - ], - "properties": { - "vote": { - "type": "object", - "required": [ - "proposal_id", - "vote" - ], - "properties": { - "proposal_id": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "vote": { - "$ref": "#/definitions/VoteOption" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "IbcMsg": { - "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", - "oneOf": [ - { - "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", - "type": "object", - "required": [ - "transfer" - ], - "properties": { - "transfer": { - "type": "object", - "required": [ - "amount", - "channel_id", - "timeout", - "to_address" - ], - "properties": { - "amount": { - "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", - "allOf": [ - { - "$ref": "#/definitions/Coin" - } - ] - }, - "channel_id": { - "description": "exisiting channel to send the tokens over", - "type": "string" - }, - "timeout": { - "description": "when packet times out, measured on remote chain", - "allOf": [ - { - "$ref": "#/definitions/IbcTimeout" - } - ] - }, - "to_address": { - "description": "address on the remote chain to receive these tokens", - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", - "type": "object", - "required": [ - "send_packet" - ], - "properties": { - "send_packet": { - "type": "object", - "required": [ - "channel_id", - "data", - "timeout" - ], - "properties": { - "channel_id": { - "type": "string" - }, - "data": { - "$ref": "#/definitions/Binary" - }, - "timeout": { - "description": "when packet times out, measured on remote chain", - "allOf": [ - { - "$ref": "#/definitions/IbcTimeout" - } - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port", - "type": "object", - "required": [ - "close_channel" - ], - "properties": { - "close_channel": { - "type": "object", - "required": [ - "channel_id" - ], - "properties": { - "channel_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "IbcTimeout": { - "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", - "type": "object", - "properties": { - "block": { - "anyOf": [ - { - "$ref": "#/definitions/IbcTimeoutBlock" - }, - { - "type": "null" - } - ] - }, - "timestamp": { - "anyOf": [ - { - "$ref": "#/definitions/Timestamp" - }, - { - "type": "null" - } - ] - } - } - }, - "IbcTimeoutBlock": { - "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", - "type": "object", - "required": [ - "height", - "revision" - ], - "properties": { - "height": { - "description": "block height after which the packet times out. the height within the given revision", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "revision": { - "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, "Link": { "type": "object", "required": [ @@ -1197,14 +964,6 @@ } ] }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, "Trigger": { "type": "object", "required": [ @@ -1232,15 +991,6 @@ "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", "type": "string" }, - "VoteOption": { - "type": "string", - "enum": [ - "yes", - "no", - "abstain", - "no_with_veto" - ] - }, "WasmMsg": { "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", "oneOf": [ diff --git a/contracts/cw-cyber-gift/schema/query_msg.json b/contracts/cw-cyber-gift/schema/query_msg.json index 838ce39..e07194f 100644 --- a/contracts/cw-cyber-gift/schema/query_msg.json +++ b/contracts/cw-cyber-gift/schema/query_msg.json @@ -111,7 +111,9 @@ ], "properties": { "stage": { - "$ref": "#/definitions/Uint64" + "type": "integer", + "format": "uint32", + "minimum": 0.0 } } } @@ -121,38 +123,14 @@ { "type": "object", "required": [ - "all_release_stage_state" + "all_release_stage_states" ], "properties": { - "all_release_stage_state": { - "type": "object", - "properties": { - "limit": { - "type": [ - "integer", - "null" - ], - "format": "uint8", - "minimum": 0.0 - }, - "start": { - "type": [ - "integer", - "null" - ], - "format": "uint8", - "minimum": 0.0 - } - } + "all_release_stage_states": { + "type": "object" } }, "additionalProperties": false } - ], - "definitions": { - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } + ] } diff --git a/contracts/cw-cyber-gift/schema/release_stage_state_response.json b/contracts/cw-cyber-gift/schema/release_stage_state_response.json index 182facb..5cf0449 100644 --- a/contracts/cw-cyber-gift/schema/release_stage_state_response.json +++ b/contracts/cw-cyber-gift/schema/release_stage_state_response.json @@ -7,13 +7,9 @@ ], "properties": { "releases": { - "$ref": "#/definitions/Uint64" - } - }, - "definitions": { - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" + "type": "integer", + "format": "uint32", + "minimum": 0.0 } } } diff --git a/contracts/cw-cyber-gift/src/contract.rs b/contracts/cw-cyber-gift/src/contract.rs index 5eda0c2..95cd6be 100644 --- a/contracts/cw-cyber-gift/src/contract.rs +++ b/contracts/cw-cyber-gift/src/contract.rs @@ -1,3 +1,4 @@ +use std::iter; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{to_binary, Binary, Decimal, Deps, DepsMut, Env, StdResult, Uint64, MessageInfo, Empty}; @@ -5,9 +6,9 @@ use cw2::{get_contract_version, set_contract_version}; use crate::error::ContractError; use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; -use crate::state::{Config, CONFIG, State, STATE}; +use crate::state::{Config, CONFIG, RELEASES_STATS, State, STATE}; use crate::execute::{execute_claim, execute_execute, execute_register_merkle_root, execute_release, execute_update_owner, execute_update_target, execute_update_treasury}; -use crate::query::{query_all_release_stage_state, query_claim, query_config, query_is_claimed, query_merkle_root, query_release_stage_state, query_release_state, query_state}; +use crate::query::{query_all_release_stage_states, query_claim, query_config, query_is_claimed, query_merkle_root, query_release_stage_state, query_release_state, query_state}; use cyber_std::CyberMsgWrapper; use semver::Version; @@ -15,7 +16,7 @@ type Response = cosmwasm_std::Response; // Version info, for migration info const CONTRACT_NAME: &str = "cyber-gift"; -const CONTRACT_VERSION: &str = "1.0.0"; +const CONTRACT_VERSION: &str = "2.0.0"; #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( @@ -50,6 +51,7 @@ pub fn instantiate( CONFIG.save(deps.storage, &config)?; STATE.save(deps.storage, &state)?; + RELEASES_STATS.save(deps.storage, &iter::repeat(0).take(100).collect())?; Ok(Response::default()) } @@ -93,7 +95,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { QueryMsg::Claim { address } => to_binary(&query_claim(deps, address)?), QueryMsg::ReleaseState { address } => to_binary(&query_release_state(deps, address)?), QueryMsg::ReleaseStageState { stage } => to_binary(&query_release_stage_state(deps, stage)?), - QueryMsg::AllReleaseStageState {start, limit} => to_binary(&query_all_release_stage_state(deps, start, limit)?), + QueryMsg::AllReleaseStageStates {} => to_binary(&query_all_release_stage_states(deps)?), } } @@ -123,5 +125,7 @@ pub fn migrate( set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; } + RELEASES_STATS.save(deps.storage, &iter::repeat(0).take(100).collect())?; + Ok(Response::new()) } diff --git a/contracts/cw-cyber-gift/src/execute.rs b/contracts/cw-cyber-gift/src/execute.rs index a7daf66..816b591 100644 --- a/contracts/cw-cyber-gift/src/execute.rs +++ b/contracts/cw-cyber-gift/src/execute.rs @@ -2,9 +2,9 @@ use cosmwasm_std::{Addr, attr, BankMsg, Coin, CosmosMsg, Decimal, DepsMut, Empty use crate::error::ContractError; use crate::helpers::{update_coefficient, verify_merkle_proof}; -use crate::state::{ReleaseState, CLAIM, CONFIG, MERKLE_ROOT, RELEASE, ClaimState, STATE, RELEASE_INFO}; -use cw_utils::{Expiration, DAY}; -use std::ops::{Add, Mul}; +use crate::state::{ReleaseState, CLAIM, CONFIG, MERKLE_ROOT, RELEASE, ClaimState, STATE, RELEASES_STATS}; +use cw_utils::{Expiration}; +use std::ops::{Add, Mul, Sub}; use cw_cyber_passport::msg::{QueryMsg as PassportQueryMsg}; use crate::msg::{AddressResponse, SignatureResponse}; use cw1_subkeys::msg::{ExecuteMsg as Cw1ExecuteMsg}; @@ -12,8 +12,6 @@ use cyber_std::CyberMsgWrapper; type Response = cosmwasm_std::Response; -const RELEASE_STAGES: u64 = 90; - pub fn execute_execute( deps: DepsMut, _env: Env, @@ -234,7 +232,7 @@ pub fn execute_claim( pub fn execute_release( deps: DepsMut, - env: Env, + _env: Env, info: MessageInfo, mut gift_address: String ) -> Result { @@ -247,8 +245,10 @@ pub fn execute_release( let config = CONFIG.load(deps.storage)?; let state = STATE.load(deps.storage)?; - if state.claims < config.target_claim { - return Err(ContractError::NotActivated {}); + + let mut state_stage = Uint128::new(100u128).mul(Decimal::from_ratio(state.claims, config.target_claim)); + if state_stage.ge(&Uint128::new(100u128)) { + state_stage = Uint128::new(100u128); } let mut release_state = RELEASE.load(deps.storage, gift_address.clone())?; @@ -261,40 +261,40 @@ pub fn execute_release( return Err(ContractError::GiftReleased {}); } - let amount: Uint128; + if release_state.stage.eq(&Uint64::new(state_stage.clone().u128() as u64)) { + return Err(ContractError::StageReleased {}); + } + + if release_state.stage.gt(&Uint64::new(state_stage.clone().u128() as u64)) { + return Err(ContractError::Unauthorized {}) + } + + let amount; if release_state.stage.is_zero() { - // first claim, amount 10% of claim amount = release_state .balance_claim - .mul(Decimal::percent(10)); - release_state.stage_expiration = DAY.after(&env.block); - release_state.stage = Uint64::new(RELEASE_STAGES); + .mul(Decimal::percent(state_stage.u128() as u64)); } else { - if release_state.stage_expiration.is_expired(&env.block) { - // last claim, amount is rest - if release_state.stage.u64() == 1 { - amount = release_state.balance_claim; - release_state.stage_expiration = Expiration::Never {}; - release_state.stage = Uint64::zero(); - } else { - // amount is equal during all intermediate stages - amount = release_state - .balance_claim - .mul(Decimal::from_ratio(1u128, release_state.stage)); - release_state.stage_expiration = DAY.after(&env.block); - release_state.stage = release_state.stage.checked_sub(Uint64::new(1))?; - } + if state_stage.ne(&Uint128::new(100u128)) { + amount = CLAIM.load(deps.storage, gift_address.clone())? + .claim + .sub(Uint128::from(CLAIM_BOUNTY)) + .mul(Decimal::from_ratio(state_stage.sub(Uint128::from(release_state.stage)), 100u128)) } else { - return Err(ContractError::StageReleased {}); + amount = release_state.balance_claim; } } - release_state.balance_claim = release_state.balance_claim - amount; - - RELEASE_INFO.update(deps.storage, release_state.stage.u64(), |rls: Option| -> StdResult { - Ok(rls.unwrap_or_default().add(Uint64::new(1))) + RELEASES_STATS.update(deps.storage, |mut info| -> StdResult> { + for i in (release_state.stage.u64())..(state_stage.u128() as u64) { + info[i as usize] = info[i as usize] + 1u32; + } + Ok(info) })?; + release_state.stage = Uint64::from(state_stage.u128() as u64); + release_state.balance_claim = release_state.balance_claim - amount; + RELEASE.save( deps.storage, gift_address.clone(), diff --git a/contracts/cw-cyber-gift/src/msg.rs b/contracts/cw-cyber-gift/src/msg.rs index 7d4a1bf..5b489ca 100644 --- a/contracts/cw-cyber-gift/src/msg.rs +++ b/contracts/cw-cyber-gift/src/msg.rs @@ -56,11 +56,8 @@ pub enum QueryMsg { IsClaimed { address: String }, Claim { address: String }, ReleaseState { address: String }, - ReleaseStageState { stage: Uint64 }, - AllReleaseStageState { - start: Option, - limit: Option, - }, + ReleaseStageState { stage: u32 }, + AllReleaseStageStates{} } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] @@ -111,12 +108,12 @@ pub struct ReleaseStateResponse { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct ReleaseStageStateResponse { - pub releases: Uint64, + pub releases: u32, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct AllReleaseStageStateResponse { - pub releases: Vec, + pub releases: Vec, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] diff --git a/contracts/cw-cyber-gift/src/query.rs b/contracts/cw-cyber-gift/src/query.rs index 4035133..93f43b3 100644 --- a/contracts/cw-cyber-gift/src/query.rs +++ b/contracts/cw-cyber-gift/src/query.rs @@ -1,7 +1,6 @@ -use cosmwasm_std::{Deps, Order, StdResult, Uint64}; -use cw_storage_plus::Bound; +use cosmwasm_std::{Deps, StdResult}; use crate::msg::{AllReleaseStageStateResponse, ClaimResponse, ConfigResponse, IsClaimedResponse, MerkleRootResponse, ReleaseStageStateResponse, ReleaseStateResponse, StateResponse}; -use crate::state::{CLAIM, CONFIG, MERKLE_ROOT, RELEASE, RELEASE_INFO, STATE}; +use crate::state::{CLAIM, CONFIG, MERKLE_ROOT, RELEASE, RELEASES_STATS, STATE}; pub fn query_config(deps: Deps) -> StdResult { @@ -67,23 +66,16 @@ pub fn query_release_state(deps: Deps, address: String) -> StdResult StdResult { - let release_stage_state = RELEASE_INFO.load(deps.storage, stage.u64())?; +pub fn query_release_stage_state(deps: Deps, stage: u32) -> StdResult { + let release_stage_state = RELEASES_STATS.load(deps.storage)?; let resp = ReleaseStageStateResponse { - releases: release_stage_state + releases: release_stage_state[stage as usize] }; Ok(resp) } -pub fn query_all_release_stage_state(deps: Deps, start: Option, limit: Option) -> StdResult { - let start = start.map(Bound::inclusive); - let limit = limit.unwrap_or(100) as usize; - - let all_release_stage_state = RELEASE_INFO - .range(deps.storage, start, None, Order::Ascending) - .take(limit) - .map(|item| item.unwrap().1) - .collect::>(); +pub fn query_all_release_stage_states(deps: Deps) -> StdResult { + let all_release_stage_state = RELEASES_STATS.load(deps.storage)?; let resp = AllReleaseStageStateResponse { releases: all_release_stage_state }; diff --git a/contracts/cw-cyber-gift/src/state.rs b/contracts/cw-cyber-gift/src/state.rs index df22343..1bdfe2e 100644 --- a/contracts/cw-cyber-gift/src/state.rs +++ b/contracts/cw-cyber-gift/src/state.rs @@ -55,5 +55,5 @@ pub const CLAIM: Map = Map::new(CLAIM_PREFIX); pub const RELEASE_PREFIX: &str = "release"; pub const RELEASE: Map = Map::new(RELEASE_PREFIX); -pub const RELEASE_INFO_PREFIX: &str = "release_info"; -pub const RELEASE_INFO: Map = Map::new(RELEASE_INFO_PREFIX); +pub const RELEASES_STATS_PREFIX: &str = "releases_stats"; +pub const RELEASES_STATS: Item> = Item::new(RELEASES_STATS_PREFIX); diff --git a/contracts/cw-cyber-gift/src/tests.rs b/contracts/cw-cyber-gift/src/tests.rs index cd02936..1cb4d97 100644 --- a/contracts/cw-cyber-gift/src/tests.rs +++ b/contracts/cw-cyber-gift/src/tests.rs @@ -1,33 +1,34 @@ #[cfg(test)] mod tests { + use std::borrow::BorrowMut; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; - use cosmwasm_std::{attr, from_binary, Binary, Coin, Uint128, Uint64, Empty, Addr, coins, BlockInfo}; - use crate::msg::{AllReleaseStageStateResponse, ConfigResponse, ExecuteMsg, InstantiateMsg, MerkleRootResponse, QueryMsg, ReleaseStageStateResponse, StateResponse}; + use cosmwasm_std::{attr, from_binary, Binary, Coin, Uint128, Uint64, Empty, Addr, coins}; + use crate::msg::{AllReleaseStageStateResponse, ConfigResponse, ExecuteMsg, InstantiateMsg, MerkleRootResponse, QueryMsg}; use crate::ContractError; use crate::contract::{execute, instantiate, query}; use cw_multi_test::{next_block, Contract, ContractWrapper, Executor}; use cyber_std::{CyberMsgWrapper}; use cw_cyber_passport::msg::ExecuteMsg as PassportExecuteMsg; use cyber_std_test::CyberApp; - + use csv; + use serde::Deserialize; const NATIVE_TOKEN: &str = "boot"; const OWNER: &str = "owner"; - const CYB1: &str = "bostrom19nk207agguzdvpj9nqsf4zrjw8mcuu9afun3fv"; const SPACE1: &str = "space1"; const SPACE2: &str = "space2"; const SPACE3: &str = "space3"; const INIT_BALANCE_OWNER: Uint128 = Uint128::new(10000000000000); - const INIT_BALANCE_TREASURY: Uint128 = Uint128::new(300000000); + const INIT_BALANCE_TREASURY: Uint128 = Uint128::new(570000000); const CF_UP: Uint128 = Uint128::new(20); - const CF_DOWN: Uint128 = Uint128::new(5); + const CF_DOWN: Uint128 = Uint128::new(10); const CF: Uint128 = Uint128::new(20); - const TARGET_CLAIM: Uint64 = Uint64::new(2); + const TARGET_CLAIM: Uint64 = Uint64::new(20); - pub fn next_hour(block: &mut BlockInfo) { - block.time = block.time.plus_seconds(3600); - block.height += 1; - } + // pub fn next_hour(block: &mut BlockInfo) { + // block.time = block.time.plus_seconds(3600); + // block.height += 1; + // } pub fn contract_gift() -> Box> { let contract = ContractWrapper::new( @@ -176,136 +177,163 @@ mod tests { #[test] fn proper_flow() { - // NOTE to run tests change RELEASE_STAGES to 9 - // NOTE to run tests change CONSTITUTION to QmRX8qYgeZoYM3M5zzQaWEpVFdpin6FvVXvp6RPQK3oufV - // NOTE to run tests change duration from DAY to HOUR - let init_funds = coins(INIT_BALANCE_OWNER.u128(), NATIVE_TOKEN); let mut app = mock_app(&init_funds); let (gift_addr, passport_addr, treasury_addr) = setup_contracts(&mut app); - let _res = app.execute_contract( - Addr::unchecked(OWNER), - gift_addr.clone(), - &ExecuteMsg::RegisterMerkleRoot { - merkle_root: "96c287db438923b77acee90e134e1f2d9bc506bc5544eab8e89e8886b83ca5c7".to_string() - }, - &[], - ); - - let _res = app.execute_contract( - Addr::unchecked(CYB1), - passport_addr.clone(), - &PassportExecuteMsg::CreatePassport { - nickname: "passport1".to_string(), - avatar: "QmVPRR3i2oFRjgMKS5dw4QbGNwdXNoYxfcpS3C9pVxHEbb".to_string(), - signature: Binary::from_base64("eyJwdWJfa2V5IjoiQStNWEZwN1llTE12b1ZsQVU2NlV1MHozV3RjOUN1d3EwZW9jVWh0Tk9tbnciLAoic2lnbmF0dXJlIjoicGRWNHhVY1RCT3loMFNFY2dWRnJxYUc4cXBOSHJocktLZGRxdzJ5d3Eyb2NVWGpybDNDdW8rZlRtUjR4bUpucGVIQi90blM4NEF2K0FuUnlRSlJ1S0E9PSJ9").unwrap(), - }, - &[], - ); - - let _res = app.execute_contract( - Addr::unchecked(CYB1), - passport_addr.clone(), - &PassportExecuteMsg::ProofAddress { - nickname: "passport1".to_string(), - address: "0x0408522089294b8b3f0c9514086e6ae1df00394c".to_string(), - signature: Binary::from_base64("0xa3b7b3adee5805488a62d96ca58ccee80a65a3f74343d1e6f19b0b597afe65da123c020cb968ca141d48b844b098ee33ad5aa827b0da89fb3b89ea272f9a42b01b").unwrap(), - }, - &[], - ); + #[derive(Debug, Deserialize)] + struct GiftData { + amount: u128, + nickname: String, + avatar: String, + ethereum_address: String, + bostrom_address: String, + cosmos_address: String, + proof_ethereum_msg_sig: String, + proof_bostrom_msg_sig: String, + proof_cosmos_msg_sig: String, + ethereum_proof: String, + cosmos_proof: String, + } - let _res = app.execute_contract( - Addr::unchecked(CYB1), - passport_addr.clone(), - &PassportExecuteMsg::CreatePassport { - nickname: "passport2".to_string(), - avatar: "QmVPRR3i2oFRjgMKS5dw4QbGNwdXNoYxfcpS3C9pVxHEbb".to_string(), - signature: Binary::from_base64("eyJwdWJfa2V5IjoiQStNWEZwN1llTE12b1ZsQVU2NlV1MHozV3RjOUN1d3EwZW9jVWh0Tk9tbnciLAoic2lnbmF0dXJlIjoicGRWNHhVY1RCT3loMFNFY2dWRnJxYUc4cXBOSHJocktLZGRxdzJ5d3Eyb2NVWGpybDNDdW8rZlRtUjR4bUpucGVIQi90blM4NEF2K0FuUnlRSlJ1S0E9PSJ9").unwrap(), - }, - &[], - ); + impl GiftData { + fn ethereum_proof_vec(&self) -> Vec { + self.ethereum_proof.replace(&['[',']','\''][..],"").split(",").map(|x| x.parse::().unwrap()).collect() + } - let _res = app.execute_contract( - Addr::unchecked(CYB1), - passport_addr.clone(), - &PassportExecuteMsg::ProofAddress { - nickname: "passport2".to_string(), - address: "bostrom19nk207agguzdvpj9nqsf4zrjw8mcuu9afun3fv".to_string(), - signature: Binary::from_base64("eyJwdWJfa2V5IjoiQStNWEZwN1llTE12b1ZsQVU2NlV1MHozV3RjOUN1d3EwZW9jVWh0Tk9tbnciLAoic2lnbmF0dXJlIjoicGRWNHhVY1RCT3loMFNFY2dWRnJxYUc4cXBOSHJocktLZGRxdzJ5d3Eyb2NVWGpybDNDdW8rZlRtUjR4bUpucGVIQi90blM4NEF2K0FuUnlRSlJ1S0E9PSJ9").unwrap(), - }, - &[], - ); + fn cosmos_proof_vec(&self) -> Vec { + self.cosmos_proof.replace(&['[',']','\''][..],"").split(",").map(|x| x.parse::().unwrap()).collect() + } + } - let _res = app.execute_contract( - Addr::unchecked(CYB1), - gift_addr.clone(), - &ExecuteMsg::Claim { - nickname: "passport1".to_string(), - gift_claiming_address: "0x0408522089294b8b3f0c9514086e6ae1df00394c".to_string(), - gift_amount: Uint128::new(10000000), - proof: vec!["020feac4e445b8710e223ef9d32d60d0fa060e5a33c421c217ac4976641afa9f".to_string()], - }, - &[], - ); + let mut test_data = csv::Reader::from_path("test-data-20.csv").unwrap(); + let mut data: Vec = Vec::new(); + for result in test_data.deserialize() { + let gift_data: GiftData = result.unwrap(); + data.push(gift_data) + } let _res = app.execute_contract( - Addr::unchecked(CYB1), + Addr::unchecked(OWNER), gift_addr.clone(), - &ExecuteMsg::Claim { - nickname: "passport2".to_string(), - gift_claiming_address: "bostrom19nk207agguzdvpj9nqsf4zrjw8mcuu9afun3fv".to_string(), - gift_amount: Uint128::new(5000000), - proof: vec!["c0d07d81376100727f8de10cbbc3f46c04c13a906c4a8de884abebaa94d33737".to_string()] + &ExecuteMsg::RegisterMerkleRoot { + merkle_root: "1d9d3cfc8527c79b1dd338d48a3ba15c4d5430bafb140a241b24364d521739cd".to_string() }, &[], ); - for i in 0..10 { - let res = app.execute_contract( - Addr::unchecked(CYB1), - gift_addr.clone(), - &ExecuteMsg::Release { - gift_address: "0x0408522089294b8b3f0c9514086e6ae1df00394c".to_string(), + for obj in &data { + let _ = app.execute_contract( + Addr::unchecked(obj.bostrom_address.clone()), + passport_addr.clone(), + &PassportExecuteMsg::CreatePassport { + nickname: obj.nickname.clone(), + avatar: obj.avatar.clone(), + signature: Binary::from_base64(&obj.proof_bostrom_msg_sig.clone()).unwrap(), }, &[], ); - println!("Release [ETH][{:?}]- {:?}", i, res); - let res = app.execute_contract( - Addr::unchecked(CYB1), - gift_addr.clone(), - &ExecuteMsg::Release { - gift_address: "bostrom19nk207agguzdvpj9nqsf4zrjw8mcuu9afun3fv".to_string(), + let _ = app.execute_contract( + Addr::unchecked(obj.bostrom_address.clone()), + passport_addr.clone(), + &PassportExecuteMsg::ProofAddress { + nickname: obj.nickname.clone(), + address: obj.ethereum_address.clone(), + signature: Binary::from_base64(&obj.proof_ethereum_msg_sig.clone()).unwrap(), }, &[], ); - println!("Release [CMS][{:?}]- {:?}", i, res); - app.update_block(next_hour); + let _ = app.execute_contract( + Addr::unchecked(obj.bostrom_address.clone()), + passport_addr.clone(), + &PassportExecuteMsg::ProofAddress { + nickname: obj.nickname.clone(), + address: obj.cosmos_address.clone(), + signature: Binary::from_base64(&obj.proof_cosmos_msg_sig.clone()).unwrap(), + }, + &[], + ); } + fn claim_and_release(app: &mut CyberApp, gift_addr: &Addr, treasury_addr: &Addr, data: &Vec, a: usize, b: usize, c: usize, d: usize) { + for i in a..b { + let _ =app.execute_contract( + Addr::unchecked(data[i].bostrom_address.clone()), + gift_addr.clone(), + &ExecuteMsg::Claim { + nickname: data[i].nickname.clone(), + gift_claiming_address: data[i].cosmos_address.clone(), + gift_amount: Uint128::from(data[i].amount.clone()), + proof: data[i].cosmos_proof_vec() + }, &[], + ); + + let _ =app.execute_contract( + Addr::unchecked(data[i].bostrom_address.clone()), + gift_addr.clone(), + &ExecuteMsg::Claim { + nickname: data[i].nickname.clone(), + gift_claiming_address: data[i].ethereum_address.clone(), + gift_amount: Uint128::from(data[i].amount.clone()), + proof: data[i].ethereum_proof_vec() + }, &[], + ); + + let _ =app.execute_contract( + Addr::unchecked(data[i].bostrom_address.clone()), + gift_addr.clone(), + &ExecuteMsg::Release { + gift_address: data[i].cosmos_address.clone(), + }, &[], + ); + + let _ =app.execute_contract( + Addr::unchecked(data[i].bostrom_address.clone()), + gift_addr.clone(), + &ExecuteMsg::Release { + gift_address: data[i].ethereum_address.clone(), + }, &[], + ); + } + let rel: AllReleaseStageStateResponse = app.wrap().query_wasm_smart(gift_addr, &QueryMsg::AllReleaseStageStates {}).unwrap(); + println!("RELEASES - {:?}", rel.releases); + println!("TREASURY BAL - {:?}", app.wrap().query_balance(treasury_addr, "boot").unwrap()); + + for i in c..d { + let _ = app.execute_contract( + Addr::unchecked(data[i].bostrom_address.clone()), + gift_addr.clone(), + &ExecuteMsg::Release { + gift_address: data[i].cosmos_address.clone(), + }, &[], + ); + + let _ =app.execute_contract( + Addr::unchecked(data[i].bostrom_address.clone()), + gift_addr.clone(), + &ExecuteMsg::Release { + gift_address: data[i].ethereum_address.clone(), + }, &[], + ); + } + let rel: AllReleaseStageStateResponse = app.wrap().query_wasm_smart(gift_addr, &QueryMsg::AllReleaseStageStates {}).unwrap(); + println!("RELEASES - {:?}", rel.releases); + println!("TREASURY BAL - {:?}", app.wrap().query_balance(treasury_addr, "boot").unwrap()); + println!("RELEASES - {:?}", "-------------"); + } - println!("GIFT BAL - {:?}", app.wrap().query_balance(&gift_addr, "boot").unwrap()); - println!("TREASURY BAL - {:?}", app.wrap().query_balance(&treasury_addr, "boot").unwrap()); - println!("PASSPORT #1 BAL- {:?}", app.wrap().query_balance(&Addr::unchecked(CYB1), "boot").unwrap()); + claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 0, 5, 0, 5); + claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 5, 10, 0, 10); + claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 10, 15, 0, 15); + claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 15, 19, 0, 19); + claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 19, 20, 0, 20); - for i in 0..10 { - let info: ReleaseStageStateResponse = app.wrap().query_wasm_smart( - &gift_addr, - &QueryMsg::ReleaseStageState { stage: Uint64::from(1u64) } - ).unwrap(); - println!("STAGE {:?} - RELEASES {:?}", i, info.releases.u64()); + for i in 0..20 { + println!("PASSPORT #{:?} BAL- {:?}", i, app.wrap().query_balance(&Addr::unchecked(data[i].bostrom_address.clone()), "boot").unwrap()); } - let info: StateResponse = app.wrap().query_wasm_smart(&gift_addr, &QueryMsg::State {}).unwrap(); - println!("STATE - {:?}", info); - - let res: AllReleaseStageStateResponse = app.wrap().query_wasm_smart( - &gift_addr, - &QueryMsg::AllReleaseStageState {start:Some(7u8), limit:Some(2u8)} - ).unwrap(); - println!("RELEASES - {:?}", res); } #[test] diff --git a/contracts/cw-cyber-gift/test-data-20.csv b/contracts/cw-cyber-gift/test-data-20.csv new file mode 100644 index 0000000..9d09c82 --- /dev/null +++ b/contracts/cw-cyber-gift/test-data-20.csv @@ -0,0 +1,21 @@ +n,amount,nickname,avatar,ethereum_address,bostrom_address,cosmos_address,proof_ethereum_msg_sig,proof_bostrom_msg_sig,proof_cosmos_msg_sig,ethereum_proof,cosmos_proof +0,1000000,john16748049530,QmXsQqFV682jDsrmitHGadLUTY1wrqFCFyxoRwFgLr215e,0x2a0870e4a20b7ac89d93736526f7229afe19e069,bostrom1vxtwz2k4w3gslf4j5443m2r793myjtmccg5sqa,cosmos1vxtwz2k4w3gslf4j5443m2r793myjtmcmmqr76,0x801f9fbde32248c20254dd451c7d2fa991c2654a61bc7c2c9cde194f1a356b7b14a7ef779bb889308124b1ceac8ce63ef044e66fe12e3e7779f75ebcd986c7d71c,eyJwdWJfa2V5IjoiQXAwK0xpZ2EyWllUMncrci85R0pIeUhGN0J3cG0zeERBb1kwSFJRck1NL0QiLCJzaWduYXR1cmUiOiI1TjZpV3FrcXBPMW5hV0diUkUvZEJpTzA3UW1uRDZyQjZXMmIxQ0VQSGFNTnl0UXNRd3FrRG43dFd4ZUZOQzdqcDdmTUJ2b2gzUGVlL3J0eWtKamR1dz09In0=,eyJwdWJfa2V5IjoiQXAwK0xpZ2EyWllUMncrci85R0pIeUhGN0J3cG0zeERBb1kwSFJRck1NL0QiLCJzaWduYXR1cmUiOiJSSXBIdk9OMWUzeU9qYVBCS29BZys2NHJVRGJRV3BJSms0WDNPTXZmWmVodHZmdktGaVJLMFgvVkYwc2JsVk0yaFk4TkJyd2tnYXA3NmNZemg3VUh6dz09In0=,"['48a2ca321c292e0edbb95abe1330e13351073f4e4b4b99000b22eeceb1739489','f9774aea4e0a9a5df512cd73cbd9d2ab17097f6cb0974709c5ee67d594ac4649','d7296c42082bb2f36d4e440d635e98c720b25fbd535edfcca9c30721f7389138','7e1558280233ae418e4b7267e2bf477d2e304ae6ab8c94bfbfe8d7e3cba0d2b5','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['02452801dacc1463666e46dbd1df23a64e6adf656e5ff215e44d5004a27788a4','7eeede145644f83c8cd93cfd935b23e69d82455505c9cd550fef7cbbb2da176f','987c8b89717a1dbd3232a35ea30214026c0e973369786ad31bafacbeebe7c188','b08c7b3239100ddde7a3c9799a7bd010ff8a015297ade4d28d2a92af11bab26c','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +1,1000000,john16748049531,QmWag8bM4sfHF9CfQi17LJJismqfQiipCfEJ1uBGvTXcyW,0x1e626a59052b8a710a60d9022d7d710ecb49230c,bostrom1zfshvs3ymxstv5sgyarf3feskevjvssnn2rh2d,cosmos1zfshvs3ymxstv5sgyarf3feskevjvssnsehy52,0x79834a9d9be37ba2c9a7a365bb845dd2936bac837cc13b565c175b959508e3a476e0d7a4e71d5fd5856e7545b612f5d7234d431dfc845b3a14148fc35fdab9ab1b,eyJwdWJfa2V5IjoiQTQ3L3g3RTYrQzFoQXA0MXc3Si9SelMwNkFOZDJ4UW5QRTNlaktNVVRSWEUiLCJzaWduYXR1cmUiOiJsQ0lYYjNramVYVm15cHB5MkszcG95T0ZtK1RzNVRSa1ZqYjkrS1dMeEl0NGxvSHJzeERYRFFCenpBL2dyUk9WSFBNS0Y1SzRMVURBQWtKTVo4Zk1Xdz09In0=,eyJwdWJfa2V5IjoiQTQ3L3g3RTYrQzFoQXA0MXc3Si9SelMwNkFOZDJ4UW5QRTNlaktNVVRSWEUiLCJzaWduYXR1cmUiOiI3TE5BcnRmYS9TMkdZTzVZMlQ0bmRVSlVsalpRTWZkMkUrNmUwcHV0U240NCtwcjhCMmhYRmFEbmsvYjV2MGUzR3ZmV2l4N2EvSGsrRzlIc0JOZUptQT09In0=,"['f7320bc32050bae61303ac1af65e312b3adf466900eab419d13d3f5433236fee','94153496e94f7d453562cb3d7ca41796ce0817d2526ab1af9d32cbb4e6c3c10e','573ad4a81aee3ed4106a537ef689be86034ba8ca61c94d2572ae3474e81c5a7e','fd0187c1acdcdfbcbaa6c3c93f718fbbbd99c66daa771e5291eff7268b7c8856','935f79e3d7ce4647bc538aba186e5ffbd139960b363d4be696bca275dc9215a7']","['ef5f131f81d4c30033949c79701f39380977df1fc14190ad78f45e0875f15713','94153496e94f7d453562cb3d7ca41796ce0817d2526ab1af9d32cbb4e6c3c10e','573ad4a81aee3ed4106a537ef689be86034ba8ca61c94d2572ae3474e81c5a7e','fd0187c1acdcdfbcbaa6c3c93f718fbbbd99c66daa771e5291eff7268b7c8856','935f79e3d7ce4647bc538aba186e5ffbd139960b363d4be696bca275dc9215a7']" +2,1000000,john16748049532,QmUhCwzFkauBwPdsxrXYEB8uo9bUXH2WXpKwMwbzXHb1QR,0x52c9f73cfe01b0ebafd7200881f3f35187d9dd37,bostrom1tlds7kqf0q76uewty36l5ttjjuz9htr2jpzfpm,cosmos1tlds7kqf0q76uewty36l5ttjjuz9htr23jk6lu,0x725ff85a5e3b72fc6efcadef90b44298b88f2ce6c5af85a01d554b2945faf2582351bb5bc834ce2d6e35575c853793f36c4c352da44f82f87012a71ad7752ef91c,eyJwdWJfa2V5IjoiQXB4eFZlVWZDb2JFZ2lSN09Fa0ppRHhTWkdpWTFOOUNuWktDa1FscG01QnQiLCJzaWduYXR1cmUiOiJkeERoK0dNc2RiWjVRMXJPaFB4TnA5TGRIaUFlbjAwUFNVcGpHYTFFdmZkeVJTSVhFcVFpWERSeXVvdmxjYlo4UFFLRXl6UUFEamNUNjVpam1KcDVNZz09In0=,eyJwdWJfa2V5IjoiQXB4eFZlVWZDb2JFZ2lSN09Fa0ppRHhTWkdpWTFOOUNuWktDa1FscG01QnQiLCJzaWduYXR1cmUiOiJYd1VYZlY2TnZWZWZ2ZUV1SjBEOFloZWxrbm1JbDNENkgrZzdoeE04eVpWOUNKM0lIS1BrSU50Qk1rek1UdkMvaHVlS1N6NkxITDk3eGx4QUdBSWpZUT09In0=,"['93fc83612d10b329c4fb520e6dc078ecf1354350c9515a190443244902cd1c0f','6a6be3c7f238ad078d70654605234f0ca2f982c85addbc68b034271195c605da','985d714a395ee50a8439a4a677f21b2e33357231a65acea741a9429bd7a855a2','cce8281a1e4cc9470b2e8b72cde4735af707d97e4941e2a95f777cfddace1419','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['52b846dc8ff6d1435893133fb5445ea5f63a1c1d613b3a71cbce891fdb7aae7d','002bfa7b52fd62e6e8c4c6f0e70eb81495bd0dfcb567284a08134c3aa13ae3e2','d7296c42082bb2f36d4e440d635e98c720b25fbd535edfcca9c30721f7389138','7e1558280233ae418e4b7267e2bf477d2e304ae6ab8c94bfbfe8d7e3cba0d2b5','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +3,1000000,john16748049533,QmVAUQjdDS7MNx6AG9gLd4gmwkv9MSRN28CXcVR2sZC8g4,0x5efda7573677722277f77436a04289f88bcc6916,bostrom125d5h04alexe84a2pkcrd77ukyf7pln9v3x0m2,cosmos125d5h04alexe84a2pkcrd77ukyf7pln90zju9d,0xe69483f6f0c147fa85f89cce2b9ae3a090e934956a7cbdbd856d514340a1755722c6849755e1d9b4985a47a5343bb6bf9e1af20b87de15c2ef2728dcb26409d61c,eyJwdWJfa2V5IjoiQTRya0sxa2dJMTRWL3RaZjViMi9uckdid3RaaEhHRXhHOHgyZlZuZ3dNalciLCJzaWduYXR1cmUiOiJHZE16OTdsMUlSL05TYWZvZnVxblRBRVNJb2xPd05zeDdKSW1zNFMwcGZwNU9qSEtoV2lnL2JHS2J5K1RpVllBYW8rMmtpalBvRHgvNTByUFBCdTl3Zz09In0=,eyJwdWJfa2V5IjoiQTRya0sxa2dJMTRWL3RaZjViMi9uckdid3RaaEhHRXhHOHgyZlZuZ3dNalciLCJzaWduYXR1cmUiOiJGbDg5MzB4UFlIVlZ5UmdCTWRYZzU1NnZHUnI0VXlHV1VJYS9qcGdUUzlCa2lwZlVtZDVjeDBmRFpTY2thUklBbXhWS244bzhya1k2Q3Q1SWpENjdnUT09In0=,"['261dbb1c75a5f59187d7bb97a16afc40a1b90cae699b7a87cded2c5d0bb65a1a','7ff201afd2e46ba9bf8c7288c3a5ba74eefe4ece2ce1ba278fa4f3ae05190415','f2326ac0fbf8dbb5aee5b4fc4374fcd7a75ef949b193ccc6f1df5595af7548f6','7e1558280233ae418e4b7267e2bf477d2e304ae6ab8c94bfbfe8d7e3cba0d2b5','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['834bbdeeeea567b301ad689f53a05d618c67b60d76188fee4b242df2dff187a2','80a57699abb4b7b914771fac1a6339ae93838d01b310a8d77aa87f517540be77','d518297c68d5b4a5e47bccc7194fefd69caa1c76ab127ca050e2ecfe24b11209','d5eee0113fed9d4d67d29ae42e8bab56dea9635a7c1fd3c17035b84e31126741','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +4,1000000,john16748049534,QmVtqporVk1vrW9ePe3RFSWbMhGCrzMuG2g5LGFdKe1W4E,0x978ca33e1dc6158a9c1ef3f927c00f9cfe874a26,bostrom1autrq2nvr7tna65tsr63smp6ta044y9yjevktl,cosmos1autrq2nvr7tna65tsr63smp6ta044y9y32c94c,0xa04705fcfe006a324e60e503d395da731533d55de44595140b75de5bbb73dbf26c6d3ef13d7fd8aad9d941991768d1034630973787b1dcffc0e8e220f08fdb711c,eyJwdWJfa2V5IjoiQTFrNk5zUEQ2dWxGcjZsVlFXeC9HY2F4VFNDeHhDRU5LU2V4WVNFdS9JUjIiLCJzaWduYXR1cmUiOiJXUWswZFZvbWJGeFVoYkJrQ0N5b25hUUhHaEZoK2N0dTdpUFlnSERRQXpSN0l5czF4SHp1dG40aVg2UXJwVHdmRlhiVjUxVFVUUmFIRno2bkNFRURHdz09In0=,eyJwdWJfa2V5IjoiQTFrNk5zUEQ2dWxGcjZsVlFXeC9HY2F4VFNDeHhDRU5LU2V4WVNFdS9JUjIiLCJzaWduYXR1cmUiOiJXdWJ1NmJwWVI3UmFBVFBxSXhpb1o2bDJGa3k2eUxtNTFRVGdlRitpZDN3cGRGOERVQUxrMkNBek9wVkwrbWdlemx6Y3BLOFcyUnBGQmlBK3R6aDljQT09In0=,"['e2232f74b3387788f6dc5e2821faa1e68570aff8956872c5e0b4f4cd0250de87','ff1cf7ef1f53703f02179657a10e63008dd5616a6ad5145333e237e85752f82e','573ad4a81aee3ed4106a537ef689be86034ba8ca61c94d2572ae3474e81c5a7e','fd0187c1acdcdfbcbaa6c3c93f718fbbbd99c66daa771e5291eff7268b7c8856','935f79e3d7ce4647bc538aba186e5ffbd139960b363d4be696bca275dc9215a7']","['a880d078e87234870cad2327ad82e29d761a2ea8d38cce96f00d96dd336d43ce','67cc101aedbec54fa49b982ad8fdf139cb451bc1d6bdae335827ffb41653ca90','985d714a395ee50a8439a4a677f21b2e33357231a65acea741a9429bd7a855a2','cce8281a1e4cc9470b2e8b72cde4735af707d97e4941e2a95f777cfddace1419','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +5,1000000,john16748049535,QmPdhLq5m5j34s5V6taBZUyCHi8NfjmpMa6TdnQzcQPNHo,0x39ced01a2be781ad7e6985bb54338547a8dad0b6,bostrom17zzmyecv70u244nq6pngl8hhtzjuay27lpm895,cosmos17zzmyecv70u244nq6pngl8hhtzjuay27uj05mn,0x676010d367e4abb429890d4cf46a035819215953dd3698ba1f952f85595bea5208bc09e105d255066758c0ed112a5a4e47a82cca5eca1844a8033f633371ee511c,eyJwdWJfa2V5IjoiQS9rRExENEtybUN0VDRCVjljUUphMHZOVk5WcUgvYVNBbllXNGYwZjB5NSsiLCJzaWduYXR1cmUiOiJnNWNsanlGZkU1UXJtNUxKKzAwcjh2RFNDMzlJOG5ISGxxMHpvVVRsL04wcm9IUjdVbHlEZjdZaHB4NHcwRTBoVytxejZ6TGhITUVDYXlWRlV6MEJBQT09In0=,eyJwdWJfa2V5IjoiQS9rRExENEtybUN0VDRCVjljUUphMHZOVk5WcUgvYVNBbllXNGYwZjB5NSsiLCJzaWduYXR1cmUiOiJTYkRzMU56cUVPMStQNFZzcE5kSlY4dm9YdHdMUEdDNzVVVXJFbkg1UkhKWGJsUENDdU45SmFDSzJveFlhU0h1bVptNmxVeXlCdVJlcHNJMFcrSkdzQT09In0=,"['6d713fac74e6a9e7b4c5cb3641acaa0fb98327c5974748527e4699825e1cbd9e','5455dff45a7d63c164dbb48f661c1248ee6bdf507d82a4dc7d32d1aa3d1b823e','071e121394b0ff13d805995d9b058b88ef19d9fd46ddb05bd34f60c56465e808','d5eee0113fed9d4d67d29ae42e8bab56dea9635a7c1fd3c17035b84e31126741','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['da3ee6d18f45d2ec29cf0ce002a49dca3f52201395fee0788adbc5df3f59a6e0','80c822460728261793cd9b4cb81bd7241ad54dc2812f5a8212bfe76432f318b5','3ec168989292dff347540bcdac4c81bee186180f62445aa4b4eddb197059a3d5','fd0187c1acdcdfbcbaa6c3c93f718fbbbd99c66daa771e5291eff7268b7c8856','935f79e3d7ce4647bc538aba186e5ffbd139960b363d4be696bca275dc9215a7']" +6,1000000,john16748049536,QmYB6AYDjZRq31yn8QaYLfqkFxrsS3yjfz1dYtPKampcWV,0x809c97dac3719a012684cb8059e5875d9df6fde9,bostrom1vp7hwwky7y9fuu2scfvfnm9lq8gjva3a4d0tz4,cosmos1vp7hwwky7y9fuu2scfvfnm9lq8gjva3ak7mcuj,0x7b48d2f3fc8bbb9c14202afb97ba3fe8e73209125c2e9f980770f5a3c65987c1391e162cba4cac8abd1fe0db8d8559b192c4b904d270ad587b6e50ef4f55ecf21b,eyJwdWJfa2V5IjoiQWt5NHF4MnE0c2xxckQrQlJrTnpRTTZkS2lZNlVZdXN3ckt5cXBzWGh4ZXUiLCJzaWduYXR1cmUiOiJ2TXViS2dmcHBzZG9tMm5Nck9hYUJSbkN5SlhDejJMaVd3elNnZlhRdFdnamNoY3p1Rm9nU3dMaDVvQVhSWTFJYlZFTWJWUWRReDJXRUVIelZrYmpPQT09In0=,eyJwdWJfa2V5IjoiQWt5NHF4MnE0c2xxckQrQlJrTnpRTTZkS2lZNlVZdXN3ckt5cXBzWGh4ZXUiLCJzaWduYXR1cmUiOiJyaFZvMlNmdVBhTzBHdjBCb2VrQUdOdHFPdVhWOXFPMndkWEVuV3RkNjZoL3pRQWk2cHcyV1VKTkY1ZmtmR2h6b2JwVFBzeUE2Wk9zVXN5ZndaYkp6dz09In0=,"['31eb68b6ddaf438431cf76f5d1f04754f67ba847ce178928f945de4bee629638','7ff201afd2e46ba9bf8c7288c3a5ba74eefe4ece2ce1ba278fa4f3ae05190415','f2326ac0fbf8dbb5aee5b4fc4374fcd7a75ef949b193ccc6f1df5595af7548f6','7e1558280233ae418e4b7267e2bf477d2e304ae6ab8c94bfbfe8d7e3cba0d2b5','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['187e009e290b5345eafa98ffee927892743c9a9ab084e1e0022f17f3e8ef04e6','7667886fd4d5b9420715b3b9fed47e7c5709896176bbcad6aa870e6bce09c73d','234057d82d6931ccca032c3b44bded7b0cfad4d7d49f7d46bb968adf60ec46bb','b08c7b3239100ddde7a3c9799a7bd010ff8a015297ade4d28d2a92af11bab26c','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +7,1000000,john16748049537,QmX8UzNtdyJ7g2u4s1PiKyf4NMVi6oXFKWircsHU6x6Tns,0xc7138bbebe5e6b1d26b63205de48ab3d40f221da,bostrom1efr65up36t9jv43yccqe88ykphua23hpkphcw5,cosmos1efr65up36t9jv43yccqe88ykphua23hp4jrtsn,0x12abd8933e64a509038063bdd4264c6acf7345e0bcefe9bedd3f486d5b1d52b554ce0cd8457a5b17ff7f80081ec5e9a3c2a47fbb7aac443b77ce53e4b6199e3e1c,eyJwdWJfa2V5IjoiQXk5ek5Fb2RvSVlRUVVidTRPcDZMcW05VWNHVVkyZWFRNlAwWURjalVCc0siLCJzaWduYXR1cmUiOiJ4UTJ6eVZiMGZWVW9kRTlIcGFVbUZUdDNBMG1TWGJwb1JDcVpGNTNucGZJWGsvVkdVQjFFM3owelZqMGRkN3doaTltUE1QaW9tZXR1TGZNNHdwbmUxZz09In0=,eyJwdWJfa2V5IjoiQXk5ek5Fb2RvSVlRUVVidTRPcDZMcW05VWNHVVkyZWFRNlAwWURjalVCc0siLCJzaWduYXR1cmUiOiJzUWZZNi9td3pJSExMRS80OXh1ZUlrOGlhY200NzlmTTRVZ0ZVUWtPUzFaaksvQ2ozNk52M3NrTDd1eWFwTndUc1MzVjZON3MyZ0JTMGUxUXJLbDFqdz09In0=,"['0c971adf8d38f88766c4ff8e668868b48b3b41ad9ac69fb1004fd708a964ee5c','74ed77ed2a54bb5d74f6ba0d945e0ccf4b22bc2d5ec71c2cf79e55460b23a4f2','987c8b89717a1dbd3232a35ea30214026c0e973369786ad31bafacbeebe7c188','b08c7b3239100ddde7a3c9799a7bd010ff8a015297ade4d28d2a92af11bab26c','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['adcff6ccb961c9b9d24733c090ee02d6feb7a0b5b84bd8df06f5c7acce7d28c2','46dadebdbaa94fdffa4c52c495dccbcbc73f2bb77a5ef7e53aed9e31e6195d7d','3f4e1fcf490c4a733954c76c55e0c1fe3fee7c11dabb69f6a3727afae2c5222b','cce8281a1e4cc9470b2e8b72cde4735af707d97e4941e2a95f777cfddace1419','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +8,1000000,john16748049538,Qmeu9oVV2bE6r7iFdnVYLdZBTMkJyshzaASBZuf5mgCJGg,0x2a38364b6825190449cc0f0aa4a6ca34e48c5ba7,bostrom1jrtlmy48svy46a7pwppfr0qqwyyxfjwh0l2yyy,cosmos1jrtlmy48svy46a7pwppfr0qqwyyxfjwhvv7h6r,0x9efa08b8a6e913dc9cabca78df6ececdaaec8eec458a5fccba4059e936aa465a25bce99f5b7140e5e0c0e4f7d15f470d190bb4b50bcee94175c5519a72d4fa491b,eyJwdWJfa2V5IjoiQWx5WTdtVHM1L2dGdzV6OWdMblFmZ2gwQmRjcksxV1lZQ2ZxY3FOQ0VxbWoiLCJzaWduYXR1cmUiOiJWOUt4MWQxck11OFcxUmswNHZLSFk2QW12djJZdTlsYWEzZmNKbSsrSFJWZlBXb0xaS3FwRTRCWms4YTJVc3hYL3ByNStoYVk1QVJWOVM0OFNvd0pDZz09In0=,eyJwdWJfa2V5IjoiQWx5WTdtVHM1L2dGdzV6OWdMblFmZ2gwQmRjcksxV1lZQ2ZxY3FOQ0VxbWoiLCJzaWduYXR1cmUiOiJkNFlnVk1iWHdwck92Tm9RWDJZT2xZNGtQd0dJTFVmdjF1MytKekdPUlNCeDVMMFZoTVhPZWNCMFBReTduTENSQkxwM3lXTFN1VTNtUkRqYjZSRmlTQT09In0=,"['47d5128b5631f98ae5eb5e8ae02869269e02710d0a16747523aadcd39a22e118','f9774aea4e0a9a5df512cd73cbd9d2ab17097f6cb0974709c5ee67d594ac4649','d7296c42082bb2f36d4e440d635e98c720b25fbd535edfcca9c30721f7389138','7e1558280233ae418e4b7267e2bf477d2e304ae6ab8c94bfbfe8d7e3cba0d2b5','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['1429375f1d3ddb7d893a352d333c796dd870f8960a6a8ec11b8ee40481f02d46','7667886fd4d5b9420715b3b9fed47e7c5709896176bbcad6aa870e6bce09c73d','234057d82d6931ccca032c3b44bded7b0cfad4d7d49f7d46bb968adf60ec46bb','b08c7b3239100ddde7a3c9799a7bd010ff8a015297ade4d28d2a92af11bab26c','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +9,1000000,john16748049539,QmYji6dgHnVcTSfGCL5CULQp2PQ951EV7gJ39cxCiGe77b,0x3a57de3f22a20a195464bea0653ce701e4d3222f,bostrom1gag0lwpmkv8jvmj6jh0dk869q6t04aekz5xj47,cosmos1gag0lwpmkv8jvmj6jh0dk869q6t04aekp8jpte,0x04f52d0f4ab96e28b83d53d4358389d2bdc75d8cb0c245fa1200e97d464a52d20cc59461322a88828d5e2bdcb092ee21d682b52d91a36d07ffeca4dbf2e310e01b,eyJwdWJfa2V5IjoiQTNTWHNTa21FSEVjaGsyZWJJVUVsQ085U28vYklPOEZQa3MyZ2tUSGMxdXQiLCJzaWduYXR1cmUiOiIrb3BObXBwUFJGQ3EvYjFNQ2dDaTdRZ0l5eVl0RU9QU0ZsZW9sdXF0OVhncDBZOEJLSnRXNFpFbTlXVFlwVHhqejE3YWN5anQxc2Z5VTlKcytQOTkwdz09In0=,eyJwdWJfa2V5IjoiQTNTWHNTa21FSEVjaGsyZWJJVUVsQ085U28vYklPOEZQa3MyZ2tUSGMxdXQiLCJzaWduYXR1cmUiOiJCdjd2THR3eURjd1pRNXJ1bEo0RmgxcDJLQkx3K1loRit5UktkK2dJVXVjcUYyY0N0OE9NRHBKdmVYWUUxb21kMHpyU3pWZTFIQkJCQjFuc2JWSloxUT09In0=,"['086977eec15620d7e9634998fd42ec26ba8c3f098481bdb523b4fd342ca4d45e','7eeede145644f83c8cd93cfd935b23e69d82455505c9cd550fef7cbbb2da176f','987c8b89717a1dbd3232a35ea30214026c0e973369786ad31bafacbeebe7c188','b08c7b3239100ddde7a3c9799a7bd010ff8a015297ade4d28d2a92af11bab26c','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['0c04c066e8e66ace1ceab6789f07ea1df5724a0943bfe3645f9af5feaee62db2','74ed77ed2a54bb5d74f6ba0d945e0ccf4b22bc2d5ec71c2cf79e55460b23a4f2','987c8b89717a1dbd3232a35ea30214026c0e973369786ad31bafacbeebe7c188','b08c7b3239100ddde7a3c9799a7bd010ff8a015297ade4d28d2a92af11bab26c','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +10,1000000,john167480495310,QmX2qXZpxhC3yHChWEq8mUQDR5rf6K1PskYF2D3eSAtytw,0x1256619d78e02b250f8a9e98a1dd89d86e4c4070,bostrom1eye8wa6at88avvkng0mnv03ddcfryqdazvpxt9,cosmos1eye8wa6at88avvkng0mnv03ddcfryqdapl444z,0xf9e38a18ea9889acb8bc07d6aebd2b494d24244010347c603c45181a7b4e52350158ea9515e01f9bc1bb77297798f3c080b7488bc9379ffb87bb8918273f39541b,eyJwdWJfa2V5IjoiQXdhY2wrNDUvUUY3QUxadFNEdWc0UTAvN3B0RU1NdVZlb2VWZG9jS1hjVEQiLCJzaWduYXR1cmUiOiJmZWo1N2FuSElZWE5pY1NjUWJIbEk4NFpBcy9VMExvcTZuenNGUGdGd3VzeVFvdjY5QU9GZ1AyV0lJeVZqamRQSCtYM0IyeDFuUDhqMlFkRVovZWl5dz09In0=,eyJwdWJfa2V5IjoiQXdhY2wrNDUvUUY3QUxadFNEdWc0UTAvN3B0RU1NdVZlb2VWZG9jS1hjVEQiLCJzaWduYXR1cmUiOiJ6QlV1Y1hnc0Y0dlhTT2V1L3BDMUZMY25oRnNCZ0IvQnh0SGlXeDNGQUZSZi9mUklNMW9CUEEwMHpnbDExK1hGbXJqUnhjdXVHcCtFa280VW1UdS9RUT09In0=,"['be0809e6de50ed1006b97c007215299d161ef5be6ef39f60aa2f61023c00c9af','7080c2c04e801a025590d0f9da6b259e0ae8ed51a505e38f1b819da46388bf11','3f4e1fcf490c4a733954c76c55e0c1fe3fee7c11dabb69f6a3727afae2c5222b','cce8281a1e4cc9470b2e8b72cde4735af707d97e4941e2a95f777cfddace1419','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['86fea384ddc2933cbdfe0f39db0f4d23e122883d64a27002e63d5c19b0198324','80a57699abb4b7b914771fac1a6339ae93838d01b310a8d77aa87f517540be77','d518297c68d5b4a5e47bccc7194fefd69caa1c76ab127ca050e2ecfe24b11209','d5eee0113fed9d4d67d29ae42e8bab56dea9635a7c1fd3c17035b84e31126741','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +11,1000000,john167480495311,QmThUrXoXMoE3Az4dA4c17ExfdcSKDhp5PY745RmtyfwbY,0x4e1e6c637163b052817736087d296fcb83921b01,bostrom1anl2luyfxff49ve5f9v25l9twtmuje7uj3569s,cosmos1anl2luyfxff49ve5f9v25l9twtmuje7u3zqfmh,0xaf16da068872029e97aefee465266cd7a393a264548b8d609909ccc7150da1000dcd35116d865a13e0e38388c4cacefc566fbd0a4e71dbbb319af1294b5c5b961b,eyJwdWJfa2V5IjoiQTJiakM1aU5nT3Jjei94SG5zdnhSVk1CbWpnamNsQU1xaVQ5V2o1djNERnciLCJzaWduYXR1cmUiOiJsOHRUby9pakVLblcrcnhtNzVGcWU3bEhuVXErcXJOSmtEL1ovQ1VlTGlrc3NLSENYS1Jna0dlRjZSUlZ5OEg2N2VKSHFxVSt5azVoODRlNXF2Rzg3Zz09In0=,eyJwdWJfa2V5IjoiQTJiakM1aU5nT3Jjei94SG5zdnhSVk1CbWpnamNsQU1xaVQ5V2o1djNERnciLCJzaWduYXR1cmUiOiJ1a01vQzl5SUtnOHdRNTIvYmNIalpqamdzZDhyWUlKSlYrWVdQNEVrLzB0UnN2Y3BQZXpIeHhvS3MvZmJhNktyeU1pV3lYRGNEd0R4Z0oyYXYydmN2Zz09In0=,"['aca45b4d4222a45dfea628f86200267e21e91b44cb29c3a8ad5829772c69ccbc','46dadebdbaa94fdffa4c52c495dccbcbc73f2bb77a5ef7e53aed9e31e6195d7d','3f4e1fcf490c4a733954c76c55e0c1fe3fee7c11dabb69f6a3727afae2c5222b','cce8281a1e4cc9470b2e8b72cde4735af707d97e4941e2a95f777cfddace1419','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['1ea450df2eb3b0835b70ef9b2b6c14badd3e61c532e2341318eafd32fb81f95c','634840facfef6b8bdf09f0c5daba478031efaf4572983dbafc6107b6ad48ad05','234057d82d6931ccca032c3b44bded7b0cfad4d7d49f7d46bb968adf60ec46bb','b08c7b3239100ddde7a3c9799a7bd010ff8a015297ade4d28d2a92af11bab26c','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +12,1000000,john167480495312,QmQ2uudysB4vFDrEKrZ2r5L2wN6ktAHJTrZhCKi7WCxeV6,0x16c90f89dc1f409a724b0cbf81bf44e8f1050c37,bostrom1zj65hhppwq36ec5kjxmy293vscayf87w0h4jll,cosmos1zj65hhppwq36ec5kjxmy293vscayf87wvypppc,0xfcbcf57a3eb7458b16f30c01f5205411967adff852eb4e127902443b712d88d546d0320c59c768d1070e4fe1fbba3572ac5fdeb73e4fb2fd4ff665dca0aa56431b,eyJwdWJfa2V5IjoiQXJqN0pjSkFQSllnZFp5YzN1T3JIelp4VW1NOC9ZQmJSaEJNVlpIR3hlZEgiLCJzaWduYXR1cmUiOiJrVy90WTYwWXFpanRvdU51dS9sVS9XaDRYdDJVUUxmWXJYNi9ZVWFwQlpzWDR6blNzZStlYTVUUGFlSUR1Um5pc0J2Ri9PRktZcWlTSStUNmRyVFlCdz09In0=,eyJwdWJfa2V5IjoiQXJqN0pjSkFQSllnZFp5YzN1T3JIelp4VW1NOC9ZQmJSaEJNVlpIR3hlZEgiLCJzaWduYXR1cmUiOiJIUkM3TkpCQUZtUFdyZDhqMHQ5VXZqYmUwVDMrR3BldkdhSGs0VllQRUZvNnUrRnMrWlQ4UGNEWWZWSWNzSjZKMDVZcVZoSVp0TUtPLyswMkIyWGM0UT09In0=,"['9f1262e3a9eadccae15f7cc15d6795a6e5a9ec9d1adfec007d0ebe965be91b4d','6a6be3c7f238ad078d70654605234f0ca2f982c85addbc68b034271195c605da','985d714a395ee50a8439a4a677f21b2e33357231a65acea741a9429bd7a855a2','cce8281a1e4cc9470b2e8b72cde4735af707d97e4941e2a95f777cfddace1419','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['e0ffe805c4799de2086fd8dd9dd1af8f50554cfc68e563ea8da97c1586fc4517','429679ffe46e1dc31ef26f0d96a9d0a8c085b34e771b8b2cbf9da6f14b8a665d','3ec168989292dff347540bcdac4c81bee186180f62445aa4b4eddb197059a3d5','fd0187c1acdcdfbcbaa6c3c93f718fbbbd99c66daa771e5291eff7268b7c8856','935f79e3d7ce4647bc538aba186e5ffbd139960b363d4be696bca275dc9215a7']" +13,1000000,john167480495313,QmQN41T1pseftBDKsYHq2HN3HUznGP3JaS4qtvnmQ5aDiv,0xf0a94ce4992ca946e74dbf7fd23a7ce906edf500,bostrom1sge09hwek7n2g7l75jda94kxu23pvf69kj5qyf,cosmos1sge09hwek7n2g7l75jda94kxu23pvf694pqn6w,0xfaa6311e7c5ca8a12d6cd47d1ac71869a4bb91133499276968e542ea7494b7be6bf1debe31d59603c932f42dc42143209d038e04f27b9aa503263d65adf9648a1b,eyJwdWJfa2V5IjoiQXRJMGNKU084UzdLUVZOTFFjdUtMU0g0V25xT3lJWWtZblNqcENPU3ZtbGkiLCJzaWduYXR1cmUiOiJmV05IVmFTR3NYNHROSmJFN2pJa3AxV0FTcWdIMjlUTzlCcEZTZmRGL0lJMGVRd3M3MDd3VzR1NHpCTmE3OGdYMnJIc3FRRkZneGRpaWo5L1J4SGFNUT09In0=,eyJwdWJfa2V5IjoiQXRJMGNKU084UzdLUVZOTFFjdUtMU0g0V25xT3lJWWtZblNqcENPU3ZtbGkiLCJzaWduYXR1cmUiOiJwM0hSd3J2VWQ1Znlwc1FLR0Q1VjNHZDBLKzVqbDdoQVcrbENRdUNGTC9sbDA5VHN4QkdWNVFrcENYTWtCUStRUkZpTjU4ZkU4SzVZVDJJdWFHWVd4dz09In0=,"['78900d7c06c43ae20970087421f80e49257815363f6a3a3563f5ec29d28940d1','e9939065cc142edd56769e4032658a7dba904d213a6eaa4c366caff727ee838d','071e121394b0ff13d805995d9b058b88ef19d9fd46ddb05bd34f60c56465e808','d5eee0113fed9d4d67d29ae42e8bab56dea9635a7c1fd3c17035b84e31126741','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['42abbdbab55ef443e3b2a811e445d46ea549c859cbbfd72031e42cb3f409d780','13b587489a2b42666157f1f64975be2148c3ad9a2923cc2af11e2eed1156c406','f2326ac0fbf8dbb5aee5b4fc4374fcd7a75ef949b193ccc6f1df5595af7548f6','7e1558280233ae418e4b7267e2bf477d2e304ae6ab8c94bfbfe8d7e3cba0d2b5','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +14,1000000,john167480495314,QmfCqqpsMRefjrmx3QUJvAvCzo9Veu77W19tEVLMjN8LKh,0x2b7c7d4932a91bcfb7ee052ccfb24694ddf60f78,bostrom18uwscu3620qemv6w773qv60vcew3n9mvm9nnly,cosmos18uwscu3620qemv6w773qv60vcew3n9mvck8qpr,0x5f7b93e697f9837bab51daedc1203174a901d6de330a603caddc1654daa4e4015fea0533452b75d76873908c944da028a2841404f97be49137abcfbeed1327a81b,eyJwdWJfa2V5IjoiQTRyN24yTHNvYllacjg5MiszODhYR291aEFMdjk5VjlPNUp3Tnkya295VXMiLCJzaWduYXR1cmUiOiJPMitZdWZ2bzhsaVJybVYzUy9CcnFkQXh0cWFiQ05WK3h0aDRkZkhGckw1aW1xa3I0ZXhYOW9xSnB4cFVtbWJ1cllhYWRCKzF3T3B1K1E4OVZMM2xUZz09In0=,eyJwdWJfa2V5IjoiQTRyN24yTHNvYllacjg5MiszODhYR291aEFMdjk5VjlPNUp3Tnkya295VXMiLCJzaWduYXR1cmUiOiJ6R1BIVU1kZG41alZHTndHUEdDVmQ3YXIzd3JLNnJBYThjU09XZ2FhMVk1Ymp2dHpOQnVlOWVKTzZyK3Z4NkVTTWVJcVJDb29GbEdzU2pYUGdNdmlGZz09In0=,"['db43eb84d9a174a4eb7a46ff3021332ea3ff492849bd8d46d7d5d1a663454c64','429679ffe46e1dc31ef26f0d96a9d0a8c085b34e771b8b2cbf9da6f14b8a665d','3ec168989292dff347540bcdac4c81bee186180f62445aa4b4eddb197059a3d5','fd0187c1acdcdfbcbaa6c3c93f718fbbbd99c66daa771e5291eff7268b7c8856','935f79e3d7ce4647bc538aba186e5ffbd139960b363d4be696bca275dc9215a7']","['53b06263d1a01d8af4393f41bccd8334bab1ce4cf6522b8ef6a33a326225108e','002bfa7b52fd62e6e8c4c6f0e70eb81495bd0dfcb567284a08134c3aa13ae3e2','d7296c42082bb2f36d4e440d635e98c720b25fbd535edfcca9c30721f7389138','7e1558280233ae418e4b7267e2bf477d2e304ae6ab8c94bfbfe8d7e3cba0d2b5','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +15,1000000,john167480495315,QmUJ1tfzYZuk9rfyGesHQ2ctapjjgV4DHGKgN9Pk3ty2AB,0x461d118c937104f1e260e168a6a47cb58708efef,bostrom1jk5245u9tvkeqempdf5dp980qa5y3z0dpf3rhg,cosmos1jk5245u9tvkeqempdf5dp980qa5y3z0dz69sf0,0x4eeea857fff40ea49387160a083d437a1349b22f0caea73c138f47656b1c67143763a2056912f93a108c4cdadb349c37e9b6c19082b296f80a1fb1977dc0ef3b1c,eyJwdWJfa2V5IjoiQTFIcDg0ZE03NExCSXRGb09IMHJndkNIOEN5anhZRUJ4KzBqS21iYVQ1aVMiLCJzaWduYXR1cmUiOiJuU0V3ZDZXUkZRT05rcTJEM3NhS2VUai9idEpTdnBQelFOY1E0WVduQkU5clF2Y3pHWFg2NmNPTURLdXJ5VnEybU0rTitZS0ZEemR0K2lhVy9YdFRTZz09In0=,eyJwdWJfa2V5IjoiQTFIcDg0ZE03NExCSXRGb09IMHJndkNIOEN5anhZRUJ4KzBqS21iYVQ1aVMiLCJzaWduYXR1cmUiOiJqR3U4ejVLMmJhR2ZQVCtaUGdvdUtGdXBPV1Bkak85VFRuamlKM3htWVBVQk9ja1F4WDViR3N5alRPSDZKR2hoOTNJbm1SUzY5RHFtdE11ME5ob0c5dz09In0=,"['3cecd923aaf85c1ae6451d7c7c378722819528405e7625db2d98f75b05af088b','13b587489a2b42666157f1f64975be2148c3ad9a2923cc2af11e2eed1156c406','f2326ac0fbf8dbb5aee5b4fc4374fcd7a75ef949b193ccc6f1df5595af7548f6','7e1558280233ae418e4b7267e2bf477d2e304ae6ab8c94bfbfe8d7e3cba0d2b5','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['d0fff18ffb7d95e637b7c6a3c6caba360b7154d1cd926c9a493911d7405b9ebe','7080c2c04e801a025590d0f9da6b259e0ae8ed51a505e38f1b819da46388bf11','3f4e1fcf490c4a733954c76c55e0c1fe3fee7c11dabb69f6a3727afae2c5222b','cce8281a1e4cc9470b2e8b72cde4735af707d97e4941e2a95f777cfddace1419','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +16,1000000,john167480495316,QmdRdvvi2HPhdR2ZnDa5oD8NjmXYmfSSLWsAEf3igqomWV,0x9909b807aa42be119ad59548dc37a1125ef1806c,bostrom1jquzvepgx53zldx4s8gajsj6xsc4ufu25ev6jx,cosmos1jquzvepgx53zldx4s8gajsj6xsc4ufu2h2cfvp,0x4452b5f4d027af11abda63ad59e5ef5cf5e3329930c0e92e198078776788b6d51808cce3d6488ee6675808615be382fa84041f07073789d30eea92ae31dcdfb61c,eyJwdWJfa2V5IjoiQXJzcUIybnJrK3NWNjNwaGRSNHhGSFN4MTlENUEwQ1M5RXZOa09aT2pTRDUiLCJzaWduYXR1cmUiOiJwOWJxeXJSNHRpZlQvb2hiMm95aHI3aGJKekp4L2s0NVdJMTd2ZjN5Wlo1aWVvSlFkUUV2KzFUczAzRkdVbFZpWVRvclE4OEZ1bU8xMmRwOTVESVBTdz09In0=,eyJwdWJfa2V5IjoiQXJzcUIybnJrK3NWNjNwaGRSNHhGSFN4MTlENUEwQ1M5RXZOa09aT2pTRDUiLCJzaWduYXR1cmUiOiI4M2NZbjFIckxrc1Q0SncyMHZVS291bGJlTzFPQTUrZXJJdWlPZWRWdnFCZTBGYm9YaUxObko0NDM1RE5ZbFB5bEpRa1ZuWVUrOS9GMUQ4cjI3RC9Pdz09In0=,"['e1d46831e0bf6aec9ddf4abf15e5e0a67c27a6728a30ce9061f971139f713fca','ff1cf7ef1f53703f02179657a10e63008dd5616a6ad5145333e237e85752f82e','573ad4a81aee3ed4106a537ef689be86034ba8ca61c94d2572ae3474e81c5a7e','fd0187c1acdcdfbcbaa6c3c93f718fbbbd99c66daa771e5291eff7268b7c8856','935f79e3d7ce4647bc538aba186e5ffbd139960b363d4be696bca275dc9215a7']","['7bcda4c5701b49d90658d822ae13448a578949533afe90cfd5499dfe13c66e2e','f89580ed849afb7ff8f522265f4f00cae5e64152f4807215e7ff1b71de97a8ef','d518297c68d5b4a5e47bccc7194fefd69caa1c76ab127ca050e2ecfe24b11209','d5eee0113fed9d4d67d29ae42e8bab56dea9635a7c1fd3c17035b84e31126741','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" +17,1000000,john167480495317,QmYNGhg3yr75KW8G2dsunnKjHerB95ni9YYaE7hFsydcLx,0xcba395f741719483df29cee52c1dabc08d6552a4,bostrom17ev8033v0wp7l3h63hzeak80k8q0h9dtp2qral,cosmos17ev8033v0wp7l3h63hzeak80k8q0h9dtze5src,0xe7ba0ed72b4ed72f055171562f6ad26de44e4b1b66a53ab6d5da23e8226a98d82e2de562e8b45dd53ea18550312ad7e0e80827e7df7d08075537e82e5b48be651b,eyJwdWJfa2V5IjoiQWhMd29KV1RHY3dvWFk3blNUNXBBalAzeWhmNHZibkxKVW1kK3RiSmlTSlYiLCJzaWduYXR1cmUiOiJsS0FQcnhSaUVzcHUxUWRqZVc2cGJOMkNOU1pCWCs4VEZOcFZSMVcxb290VUgvZVVsZTlXa3lXL2tlRnNTQ0VUYWJpWUNTK2RMZHJJVnRYVS9rR1RSUT09In0=,eyJwdWJfa2V5IjoiQWhMd29KV1RHY3dvWFk3blNUNXBBalAzeWhmNHZibkxKVW1kK3RiSmlTSlYiLCJzaWduYXR1cmUiOiJKSVg3Ly96WlhMMGlZZlY4UUh6Zi9kY1laM0NldFkyZS9WWUk0RHgvakJNelRJY0FJWHV0dDM1bEtBZk9sZStlOVFaN2lkNVFGRWRXd2lseGV4cFBCUT09In0=,"['a951f8ef371983321bb5343e4000c0cc6b35702052b626aae2a7c2edabb66829','67cc101aedbec54fa49b982ad8fdf139cb451bc1d6bdae335827ffb41653ca90','985d714a395ee50a8439a4a677f21b2e33357231a65acea741a9429bd7a855a2','cce8281a1e4cc9470b2e8b72cde4735af707d97e4941e2a95f777cfddace1419','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['588b248bb86fdb4639ff1cb00ce33f4129ddfe03d192da246433c04f7a480704','935f79e3d7ce4647bc538aba186e5ffbd139960b363d4be696bca275dc9215a7']" +18,1000000,john167480495318,QmQYDm4FPqZzKkgRBVNGbyby69pTqy9gyJzf8qvE4vdjNE,0x24dfe5992ab27e1ff6b829d7a091f371485274a4,bostrom1xelgpwhk8najpl34rpr35884j6m0gzes6n3rp3,cosmos1xelgpwhk8najpl34rpr35884j6m0gzeseq9slk,0x26c253a1fc141b647a8c3fc0a4e57b3102bcaf7628cdb74f187c723aa655d78521a4ba365d62df54f409e558dd987efc0ddbe183242f2a262978ae3e7c24bc2a1c,eyJwdWJfa2V5IjoiQXcrQ2gzZWc4QVRRNjJkclJNQ3JaRUZNK1RQZEZDdGx2dE13YTQ5cElOS3EiLCJzaWduYXR1cmUiOiJFL3JUTHU4UmtIR3drRzA2K3RaREw3d1ZJb2h2dVdWZjZndSt4bWZzR3lVSWRoV3drcFZZVkF0NjcxR2JsTytveGkxRGNRYlYvK3NvcUJ3bmRFZmFldz09In0=,eyJwdWJfa2V5IjoiQXcrQ2gzZWc4QVRRNjJkclJNQ3JaRUZNK1RQZEZDdGx2dE13YTQ5cElOS3EiLCJzaWduYXR1cmUiOiJxcTV6Y1V6azcvREFsa1JaL0JIWkRZcFBySWtqNEZ3aGU3MVZKYSt0SGVzdDlWa1RDUEZQMlp2cXFrc2tRdnQwOFNlbTFUNm5iVkpkRWZlbjlEV2ZnUT09In0=,"['56c60204cbe826280a55b4abb0a9e058d03c6306456ef3d99483db546cb9e7e2','5455dff45a7d63c164dbb48f661c1248ee6bdf507d82a4dc7d32d1aa3d1b823e','071e121394b0ff13d805995d9b058b88ef19d9fd46ddb05bd34f60c56465e808','d5eee0113fed9d4d67d29ae42e8bab56dea9635a7c1fd3c17035b84e31126741','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['d679cd04f1181e439e69186c469036376ba88d8f8febd55e36004195fd4d9c28','80c822460728261793cd9b4cb81bd7241ad54dc2812f5a8212bfe76432f318b5','3ec168989292dff347540bcdac4c81bee186180f62445aa4b4eddb197059a3d5','fd0187c1acdcdfbcbaa6c3c93f718fbbbd99c66daa771e5291eff7268b7c8856','935f79e3d7ce4647bc538aba186e5ffbd139960b363d4be696bca275dc9215a7']" +19,1000000,john167480495319,QmSubEobcLeHbr9jxFZUVKUhmFxgWqbDkAsiZxxrQwqxtY,0x42cce5e1fdfb8e6886cb884b598598acf6ac9f6a,bostrom1yzd27qwn5922uarawlurfn2vlmpsv78ep6x7mx,cosmos1yzd27qwn5922uarawlurfn2vlmpsv78ezfjd9p,0xa64a1dd3d55895af46106d58620becca57a81354ff8a3bc904185133722fff643cbd08eb3ca1f5bab520482c88facd3eceb42f3c8e0a475c5823a5e878d4e3f41b,eyJwdWJfa2V5IjoiQXFHczVRaTVLWW1zNW1xTytQY0c3T2xlZ0h0QzRGQXVhUWVab2R0SVdmWmIiLCJzaWduYXR1cmUiOiJUUVZ4TlpIUlFqSEhoVURHYjhIT2hKSlNaSjBOTk9PSWsweDBDSmN0RjhZa2Nqem9ZUEIrMzlSTnFab25ONmVhbGFCR0VlV0tvR3F1WksraE9BTmxRZz09In0=,eyJwdWJfa2V5IjoiQXFHczVRaTVLWW1zNW1xTytQY0c3T2xlZ0h0QzRGQXVhUWVab2R0SVdmWmIiLCJzaWduYXR1cmUiOiI1SG9QWGtDU0ZlVlg0V3JwdzVGS2EyZ1ArNWNQV2RxUk1CcVlQR0M0RXZnSjNzQVBKY0tDM01HOWRMbWFDbURnL0pJdy9nWHBYZHhxWkViSzVUelBIdz09In0=,"['7cb5a055e7b463392cbbb35c23aea2fa538d048e2c2d4992aa21ffa0dc5052d3','f89580ed849afb7ff8f522265f4f00cae5e64152f4807215e7ff1b71de97a8ef','d518297c68d5b4a5e47bccc7194fefd69caa1c76ab127ca050e2ecfe24b11209','d5eee0113fed9d4d67d29ae42e8bab56dea9635a7c1fd3c17035b84e31126741','a4d58ca9cc4433cd91362d36b3d98515b9616940df00f5d81367e4d426a32e63','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']","['198d41e1b035baea1a3904137cc0860e62164d43475ed03d283b2d468ebf519b','634840facfef6b8bdf09f0c5daba478031efaf4572983dbafc6107b6ad48ad05','234057d82d6931ccca032c3b44bded7b0cfad4d7d49f7d46bb968adf60ec46bb','b08c7b3239100ddde7a3c9799a7bd010ff8a015297ade4d28d2a92af11bab26c','fc35dd9b854a30b53da1f354818f7b5f9eee48e32ea2ecb70c06831af7583cd9','04e8fecb2d4a550a20aa230632008091d06534f06b6bf2bc56efb6106cc4efee']" diff --git a/contracts/cw-cyber-passport/Cargo.toml b/contracts/cw-cyber-passport/Cargo.toml index 7bc273c..1c23a15 100644 --- a/contracts/cw-cyber-passport/Cargo.toml +++ b/contracts/cw-cyber-passport/Cargo.toml @@ -7,17 +7,6 @@ edition = "2018" [lib] crate-type = ["cdylib", "rlib"] -[profile.release] -rpath = false -lto = true -overflow-checks = true -opt-level = 3 -debug = false -debug-assertions = false -codegen-units = 1 -incremental = false -panic = 'abort' - [features] # for more explicit tests, cargo test --features=backtraces backtraces = ["cosmwasm-std/backtraces"] diff --git a/contracts/cw-cyber-passport/schema/execute_msg.json b/contracts/cw-cyber-passport/schema/execute_msg.json index bc2c9ee..e60d977 100644 --- a/contracts/cw-cyber-passport/schema/execute_msg.json +++ b/contracts/cw-cyber-passport/schema/execute_msg.json @@ -631,43 +631,6 @@ }, "additionalProperties": false }, - { - "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", - "type": "object", - "required": [ - "stargate" - ], - "properties": { - "stargate": { - "type": "object", - "required": [ - "type_url", - "value" - ], - "properties": { - "type_url": { - "type": "string" - }, - "value": { - "$ref": "#/definitions/Binary" - } - } - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "ibc" - ], - "properties": { - "ibc": { - "$ref": "#/definitions/IbcMsg" - } - }, - "additionalProperties": false - }, { "type": "object", "required": [ @@ -679,18 +642,6 @@ } }, "additionalProperties": false - }, - { - "type": "object", - "required": [ - "gov" - ], - "properties": { - "gov": { - "$ref": "#/definitions/GovMsg" - } - }, - "additionalProperties": false } ] }, @@ -1286,190 +1237,6 @@ } ] }, - "GovMsg": { - "oneOf": [ - { - "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", - "type": "object", - "required": [ - "vote" - ], - "properties": { - "vote": { - "type": "object", - "required": [ - "proposal_id", - "vote" - ], - "properties": { - "proposal_id": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "vote": { - "$ref": "#/definitions/VoteOption" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "IbcMsg": { - "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", - "oneOf": [ - { - "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", - "type": "object", - "required": [ - "transfer" - ], - "properties": { - "transfer": { - "type": "object", - "required": [ - "amount", - "channel_id", - "timeout", - "to_address" - ], - "properties": { - "amount": { - "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", - "allOf": [ - { - "$ref": "#/definitions/Coin" - } - ] - }, - "channel_id": { - "description": "exisiting channel to send the tokens over", - "type": "string" - }, - "timeout": { - "description": "when packet times out, measured on remote chain", - "allOf": [ - { - "$ref": "#/definitions/IbcTimeout" - } - ] - }, - "to_address": { - "description": "address on the remote chain to receive these tokens", - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", - "type": "object", - "required": [ - "send_packet" - ], - "properties": { - "send_packet": { - "type": "object", - "required": [ - "channel_id", - "data", - "timeout" - ], - "properties": { - "channel_id": { - "type": "string" - }, - "data": { - "$ref": "#/definitions/Binary" - }, - "timeout": { - "description": "when packet times out, measured on remote chain", - "allOf": [ - { - "$ref": "#/definitions/IbcTimeout" - } - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port", - "type": "object", - "required": [ - "close_channel" - ], - "properties": { - "close_channel": { - "type": "object", - "required": [ - "channel_id" - ], - "properties": { - "channel_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "IbcTimeout": { - "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", - "type": "object", - "properties": { - "block": { - "anyOf": [ - { - "$ref": "#/definitions/IbcTimeoutBlock" - }, - { - "type": "null" - } - ] - }, - "timestamp": { - "anyOf": [ - { - "$ref": "#/definitions/Timestamp" - }, - { - "type": "null" - } - ] - } - } - }, - "IbcTimeoutBlock": { - "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", - "type": "object", - "required": [ - "height", - "revision" - ], - "properties": { - "height": { - "description": "block height after which the packet times out. the height within the given revision", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "revision": { - "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, "LabeledAddress": { "type": "object", "required": [ @@ -1705,15 +1472,6 @@ "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", "type": "string" }, - "VoteOption": { - "type": "string", - "enum": [ - "yes", - "no", - "abstain", - "no_with_veto" - ] - }, "WasmMsg": { "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", "oneOf": [ diff --git a/contracts/cw-cyber-passport/src/execute.rs b/contracts/cw-cyber-passport/src/execute.rs index 40ee833..78e8570 100644 --- a/contracts/cw-cyber-passport/src/execute.rs +++ b/contracts/cw-cyber-passport/src/execute.rs @@ -14,7 +14,7 @@ use crate::state::{Config, CONFIG}; type Response = cosmwasm_std::Response; -const CONSTITUTION: &str = "QmcHB9GKHAKCLQhmSj71qNJhENJJg8Gymd1PvvsCQBhG7M"; +const CONSTITUTION: &str = "QmcHB9GKHAKCLQhmSj71qNJhENJJg8Gymd1PvvsCQBhG7M"; // set QmRX8qYgeZoYM3M5zzQaWEpVFdpin6FvVXvp6RPQK3oufV for test run pub const CYBERSPACE_ID_MSG: u64 = 420; pub fn execute_execute( diff --git a/contracts/cw-cyber-subgraph/Cargo.toml b/contracts/cw-cyber-subgraph/Cargo.toml index 0ecc014..a3d4a3d 100644 --- a/contracts/cw-cyber-subgraph/Cargo.toml +++ b/contracts/cw-cyber-subgraph/Cargo.toml @@ -7,17 +7,6 @@ edition = "2018" [lib] crate-type = ["cdylib", "rlib"] -[profile.release] -rpath = false -lto = true -overflow-checks = true -opt-level = 3 -debug = false -debug-assertions = false -codegen-units = 1 -incremental = false -panic = 'abort' - [features] # for more explicit tests, cargo test --features=backtraces backtraces = ["cosmwasm-std/backtraces"] From 71048af2ab6c6d907c3f49030eee3d045e827fe6 Mon Sep 17 00:00:00 2001 From: C H Date: Wed, 22 Mar 2023 18:59:26 +0800 Subject: [PATCH 2/3] Updated impl of releases stats --- contracts/cw-cyber-gift/schema/query_msg.json | 2 +- contracts/cw-cyber-gift/src/contract.rs | 9 ++++++--- contracts/cw-cyber-gift/src/execute.rs | 11 +++++------ contracts/cw-cyber-gift/src/msg.rs | 2 +- contracts/cw-cyber-gift/src/query.rs | 12 ++++++++---- contracts/cw-cyber-gift/src/state.rs | 2 +- 6 files changed, 22 insertions(+), 16 deletions(-) diff --git a/contracts/cw-cyber-gift/schema/query_msg.json b/contracts/cw-cyber-gift/schema/query_msg.json index e07194f..03079e8 100644 --- a/contracts/cw-cyber-gift/schema/query_msg.json +++ b/contracts/cw-cyber-gift/schema/query_msg.json @@ -112,7 +112,7 @@ "properties": { "stage": { "type": "integer", - "format": "uint32", + "format": "uint8", "minimum": 0.0 } } diff --git a/contracts/cw-cyber-gift/src/contract.rs b/contracts/cw-cyber-gift/src/contract.rs index 95cd6be..490b870 100644 --- a/contracts/cw-cyber-gift/src/contract.rs +++ b/contracts/cw-cyber-gift/src/contract.rs @@ -1,4 +1,3 @@ -use std::iter; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{to_binary, Binary, Decimal, Deps, DepsMut, Env, StdResult, Uint64, MessageInfo, Empty}; @@ -51,7 +50,9 @@ pub fn instantiate( CONFIG.save(deps.storage, &config)?; STATE.save(deps.storage, &state)?; - RELEASES_STATS.save(deps.storage, &iter::repeat(0).take(100).collect())?; + for i in 0..100 { + RELEASES_STATS.save(deps.storage, i as u8, &(0 as u32))?; + } Ok(Response::default()) } @@ -125,7 +126,9 @@ pub fn migrate( set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; } - RELEASES_STATS.save(deps.storage, &iter::repeat(0).take(100).collect())?; + for i in 0..100 { + RELEASES_STATS.save(deps.storage, i as u8, &(0 as u32))?; + } Ok(Response::new()) } diff --git a/contracts/cw-cyber-gift/src/execute.rs b/contracts/cw-cyber-gift/src/execute.rs index 816b591..4d09940 100644 --- a/contracts/cw-cyber-gift/src/execute.rs +++ b/contracts/cw-cyber-gift/src/execute.rs @@ -285,12 +285,11 @@ pub fn execute_release( } } - RELEASES_STATS.update(deps.storage, |mut info| -> StdResult> { - for i in (release_state.stage.u64())..(state_stage.u128() as u64) { - info[i as usize] = info[i as usize] + 1u32; - } - Ok(info) - })?; + for i in (release_state.stage.u64())..(state_stage.u128() as u64) { + RELEASES_STATS.update(deps.storage, i as u8, |count| -> StdResult<_> { + Ok(count.unwrap() + 1u32) + })?; + } release_state.stage = Uint64::from(state_stage.u128() as u64); release_state.balance_claim = release_state.balance_claim - amount; diff --git a/contracts/cw-cyber-gift/src/msg.rs b/contracts/cw-cyber-gift/src/msg.rs index 5b489ca..080a111 100644 --- a/contracts/cw-cyber-gift/src/msg.rs +++ b/contracts/cw-cyber-gift/src/msg.rs @@ -56,7 +56,7 @@ pub enum QueryMsg { IsClaimed { address: String }, Claim { address: String }, ReleaseState { address: String }, - ReleaseStageState { stage: u32 }, + ReleaseStageState { stage: u8 }, AllReleaseStageStates{} } diff --git a/contracts/cw-cyber-gift/src/query.rs b/contracts/cw-cyber-gift/src/query.rs index 93f43b3..5767eec 100644 --- a/contracts/cw-cyber-gift/src/query.rs +++ b/contracts/cw-cyber-gift/src/query.rs @@ -1,4 +1,5 @@ use cosmwasm_std::{Deps, StdResult}; +use cosmwasm_std::Order::Ascending; use crate::msg::{AllReleaseStageStateResponse, ClaimResponse, ConfigResponse, IsClaimedResponse, MerkleRootResponse, ReleaseStageStateResponse, ReleaseStateResponse, StateResponse}; use crate::state::{CLAIM, CONFIG, MERKLE_ROOT, RELEASE, RELEASES_STATS, STATE}; @@ -66,16 +67,19 @@ pub fn query_release_state(deps: Deps, address: String) -> StdResult StdResult { - let release_stage_state = RELEASES_STATS.load(deps.storage)?; +pub fn query_release_stage_state(deps: Deps, stage: u8) -> StdResult { + let release_stage_state = RELEASES_STATS.load(deps.storage, stage as u8)?; let resp = ReleaseStageStateResponse { - releases: release_stage_state[stage as usize] + releases: release_stage_state }; Ok(resp) } pub fn query_all_release_stage_states(deps: Deps) -> StdResult { - let all_release_stage_state = RELEASES_STATS.load(deps.storage)?; + let all_release_stage_state = RELEASES_STATS + .range(deps.storage, None, None, Ascending) + .map(|i| i.unwrap().1) + .collect(); let resp = AllReleaseStageStateResponse { releases: all_release_stage_state }; diff --git a/contracts/cw-cyber-gift/src/state.rs b/contracts/cw-cyber-gift/src/state.rs index 1bdfe2e..1b086a6 100644 --- a/contracts/cw-cyber-gift/src/state.rs +++ b/contracts/cw-cyber-gift/src/state.rs @@ -56,4 +56,4 @@ pub const RELEASE_PREFIX: &str = "release"; pub const RELEASE: Map = Map::new(RELEASE_PREFIX); pub const RELEASES_STATS_PREFIX: &str = "releases_stats"; -pub const RELEASES_STATS: Item> = Item::new(RELEASES_STATS_PREFIX); +pub const RELEASES_STATS: Map = Map::new(RELEASES_STATS_PREFIX); From 6da5ebacdc46e40da82d8073555959c968cce130 Mon Sep 17 00:00:00 2001 From: C H Date: Mon, 17 Jul 2023 17:06:08 +0800 Subject: [PATCH 3/3] Added referral program --- contracts/cw-cyber-gift/src/contract.rs | 15 +- contracts/cw-cyber-gift/src/execute.rs | 71 +++++- .../cw-cyber-gift/src/indexed_referral.rs | 215 ++++++++++++++++++ contracts/cw-cyber-gift/src/lib.rs | 1 + contracts/cw-cyber-gift/src/msg.rs | 18 +- contracts/cw-cyber-gift/src/state.rs | 8 + contracts/cw-cyber-gift/src/tests.rs | 37 ++- 7 files changed, 341 insertions(+), 24 deletions(-) create mode 100644 contracts/cw-cyber-gift/src/indexed_referral.rs diff --git a/contracts/cw-cyber-gift/src/contract.rs b/contracts/cw-cyber-gift/src/contract.rs index 490b870..eed0bf9 100644 --- a/contracts/cw-cyber-gift/src/contract.rs +++ b/contracts/cw-cyber-gift/src/contract.rs @@ -1,6 +1,6 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; -use cosmwasm_std::{to_binary, Binary, Decimal, Deps, DepsMut, Env, StdResult, Uint64, MessageInfo, Empty}; +use cosmwasm_std::{to_binary, Binary, Decimal, Deps, DepsMut, Env, StdResult, Uint64, MessageInfo, Empty, Addr}; use cw2::{get_contract_version, set_contract_version}; use crate::error::ContractError; @@ -10,6 +10,7 @@ use crate::execute::{execute_claim, execute_execute, execute_register_merkle_roo use crate::query::{query_all_release_stage_states, query_claim, query_config, query_is_claimed, query_merkle_root, query_release_stage_state, query_release_state, query_state}; use cyber_std::CyberMsgWrapper; use semver::Version; +use crate::indexed_referral::{all_ref, all_referred_of, has_ref, ref_of, REFERRALS}; type Response = cosmwasm_std::Response; @@ -81,7 +82,8 @@ pub fn execute( gift_claiming_address, gift_amount, proof, - } => execute_claim(deps, env, info, nickname, gift_claiming_address, gift_amount, proof), + referral, + } => execute_claim(deps, env, info, nickname, gift_claiming_address, gift_amount, proof, referral), ExecuteMsg::Release { gift_address } => execute_release(deps, env, info, gift_address), } } @@ -97,6 +99,15 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { QueryMsg::ReleaseState { address } => to_binary(&query_release_state(deps, address)?), QueryMsg::ReleaseStageState { stage } => to_binary(&query_release_stage_state(deps, stage)?), QueryMsg::AllReleaseStageStates {} => to_binary(&query_all_release_stage_states(deps)?), + // TODO refactor queries + QueryMsg::ReferralOf { address } => to_binary(&ref_of(deps.storage, &Addr::unchecked(address))?), + QueryMsg::HasReferral { address } => to_binary(&has_ref(deps.storage, &Addr::unchecked(address))?), + QueryMsg::AllReferrals { + start_after, limit, is_ascending, + } => to_binary(&all_ref(deps.storage, start_after, limit, is_ascending)), + QueryMsg::AllReferredOf { + address, start_after, limit, is_ascending, + } => to_binary(&all_referred_of(deps.storage, address, start_after, limit, is_ascending)?), } } diff --git a/contracts/cw-cyber-gift/src/execute.rs b/contracts/cw-cyber-gift/src/execute.rs index 4d09940..326ce00 100644 --- a/contracts/cw-cyber-gift/src/execute.rs +++ b/contracts/cw-cyber-gift/src/execute.rs @@ -9,9 +9,13 @@ use cw_cyber_passport::msg::{QueryMsg as PassportQueryMsg}; use crate::msg::{AddressResponse, SignatureResponse}; use cw1_subkeys::msg::{ExecuteMsg as Cw1ExecuteMsg}; use cyber_std::CyberMsgWrapper; +use crate::indexed_referral::{has_ref, ref_chains, REFERRALS, set_ref}; type Response = cosmwasm_std::Response; +const CLAIM_BOUNTY: u128 = 100000; +const COMMUNITY_POOL: &str = "alice"; + pub fn execute_execute( deps: DepsMut, _env: Env, @@ -127,8 +131,6 @@ pub fn execute_register_merkle_root( ])) } -const CLAIM_BOUNTY: u128 = 100000; - pub fn execute_claim( deps: DepsMut, _env: Env, @@ -137,6 +139,7 @@ pub fn execute_claim( mut gift_claiming_address: String, gift_amount: Uint128, proof: Vec, + referral: Option, ) -> Result { gift_claiming_address = gift_claiming_address.to_lowercase(); @@ -205,6 +208,18 @@ pub fn execute_claim( Ok(stt) })?; + if referral.is_some() { + if deps.api.addr_validate(&referral.clone().unwrap())?.ne(&Addr::unchecked(res.address.clone())) { + if has_ref(deps.storage, &Addr::unchecked(res.address.clone()))?.eq(&false) { + set_ref( + deps.storage, + &Addr::unchecked(res.address.clone()), + &Addr::unchecked(referral.unwrap()) + )?; + }; + } + } + // send funds from treasury controlled by Congress Ok(Response::new() .add_message(WasmMsg::Execute { @@ -305,20 +320,52 @@ pub fn execute_release( Ok(stt) })?; - // send funds from treasury controlled by Congress + let mut messages: Vec = vec![]; + let amount_gift = Decimal::percent(80u64).mul(amount); + messages.push( + CosmosMsg::from(BankMsg::Send { + to_address: release_state.clone().address.into(), + amount: vec![Coin { + denom: config.clone().allowed_native, + amount: amount_gift, + }], + }) + ); + + if has_ref(deps.storage, &release_state.clone().address)?.eq(&true) { + let chain = ref_chains(deps.storage, &release_state.clone().address, Some(4))?; + let amount_referral = amount + .sub(amount_gift). + mul(Decimal::from_ratio(Uint128::from(1u64), Uint128::from(chain.len() as u64))); + for addr in chain.into_iter() { + messages.push(CosmosMsg::from(BankMsg::Send { + to_address: addr.into_string(), + amount: vec![Coin { + denom: config.clone().allowed_native, + amount: amount_referral, + }] + })) + } + } else { + let amount_pool = amount.sub(amount_gift); + messages.push( + CosmosMsg::from(BankMsg::Send { + to_address: String::from(COMMUNITY_POOL), + amount: vec![Coin { + denom: config.clone().allowed_native, + amount: amount_pool, + }], + }) + ); + } + + // HOW design affected with passport mapped to address (what if address will change) Ok(Response::new() .add_message(WasmMsg::Execute { contract_addr: config.treasury_addr.to_string(), msg: to_binary(&Cw1ExecuteMsg::Execute:: { - msgs: vec![ - CosmosMsg::Bank(BankMsg::Send { - to_address: release_state.clone().address.into(), - amount: vec![Coin { - denom: config.allowed_native, - amount: amount, - }], - }).into() - ]})?, + msgs: messages + })?, funds: vec![] }) .add_attributes(vec![ diff --git a/contracts/cw-cyber-gift/src/indexed_referral.rs b/contracts/cw-cyber-gift/src/indexed_referral.rs new file mode 100644 index 0000000..5bea0e0 --- /dev/null +++ b/contracts/cw-cyber-gift/src/indexed_referral.rs @@ -0,0 +1,215 @@ +use cosmwasm_std::{Addr, Order, StdError, StdResult, Storage}; +use cosmwasm_std::Order::Ascending; +use cosmwasm_std::testing::mock_dependencies; +use cw_storage_plus::{Bound, Index, IndexList, IndexedMap, MultiIndex, PrimaryKey}; + +use crate::state::{Refer, REFERRALS_PREFIX}; + +pub const DEFAULT_DEPTH: u64 = 3; +pub const DEFAULT_REFERRED_LIMIT: u64 = 50; +pub const DEFAULT_ALL_LIMIT: u64 = 100; + +pub struct ReferralIndexes<'a> { + pub referred: MultiIndex<'a, Addr, Refer, Addr>, +} + +impl IndexList for ReferralIndexes<'_> { + fn get_indexes(&'_ self) -> Box> + '_> { + let v: Vec<&dyn Index> = vec![&self.referred]; + Box::new(v.into_iter()) + } +} + +#[allow(non_snake_case)] +pub fn REFERRALS<'a>() -> IndexedMap<'a, &'a Addr, Refer, ReferralIndexes<'a>> { + let indexes = ReferralIndexes { + referred: MultiIndex::new( + |refer| refer.referrer.clone(), + REFERRALS_PREFIX, + "ref_idx", + ), + }; + IndexedMap::new(REFERRALS_PREFIX, indexes) +} + +pub fn set_ref( + storage: &mut dyn Storage, + referred_addr: &Addr, + referrer_addr: &Addr, +) -> StdResult<()> { + if referred_addr == referrer_addr { + return Err(StdError::generic_err( + "Referrer can not be same address as referral", + )); + } + + REFERRALS().save( + storage, + referred_addr, + &Refer { + referrer: referrer_addr.clone(), + referred: referred_addr.clone(), + }, + )?; + + Ok(()) +} + +pub fn ref_chains( + storage: &dyn Storage, + addr: &Addr, + depth: Option, +) -> StdResult> { + let mut chains: Vec = vec![]; + + for _ in 0..depth.unwrap_or(DEFAULT_DEPTH) { + match REFERRALS().may_load(storage, chains.last().unwrap_or(addr))? { + Some(r_addr) => chains.push(r_addr.referrer), + None => break, + }; + } + + Ok(chains) +} + +pub fn ref_of(storage: &dyn Storage, addr: &Addr) -> StdResult> { + Ok(REFERRALS().may_load(storage, addr)?.map(|r| r.referrer)) +} + +pub fn has_ref(storage: &dyn Storage, addr: &Addr) -> StdResult { + Ok(ref_of(storage, addr)?.is_some()) +} + +pub fn all_ref( + storage: &dyn Storage, + start_after: Option, + limit: Option, + is_ascending: Option, +) -> Vec { + let bound = match is_ascending.unwrap_or(true) { + true => ( + start_after + .as_ref() + .map(|e| Bound::ExclusiveRaw(e.as_bytes().to_vec())), + None, + Order::Ascending, + ), + false => ( + None, + start_after + .as_ref() + .map(|e| Bound::ExclusiveRaw(e.as_bytes().to_vec())), + Order::Descending, + ), + }; + + REFERRALS() + .range(storage, bound.0, bound.1, bound.2) + .map(|e| e.unwrap().1) + .take(limit.unwrap_or(DEFAULT_ALL_LIMIT) as usize) + .collect::>() +} + +pub fn all_referred_of( + storage: &dyn Storage, + addr: Addr, + start_after: Option, + limit: Option, + is_ascending: Option, +) -> StdResult> { + let bound = match is_ascending.unwrap_or(true) { + true => ( + start_after + .as_ref() + .map(|e| Bound::ExclusiveRaw(e.as_bytes().to_vec())), + None, + Order::Ascending, + ), + false => ( + None, + start_after + .as_ref() + .map(|e| Bound::ExclusiveRaw(e.as_bytes().to_vec())), + Order::Descending, + ), + }; + + let res = REFERRALS() + .idx + .referred + .prefix(addr) + .keys(storage, bound.0, bound.1, bound.2) + .map(|e| e.unwrap()) + .take(limit.unwrap_or(DEFAULT_REFERRED_LIMIT) as usize) + .collect::>(); + + Ok(res) +} + +#[test] +fn test_indexed_referral() { + let mut deps = mock_dependencies(); + + let a = Addr::unchecked("a"); + let bb = Addr::unchecked("bb"); + let b = Addr::unchecked("b"); + let c = Addr::unchecked("c"); + let d = Addr::unchecked("d"); + + set_ref(&mut deps.storage, &b, &a).unwrap(); + set_ref(&mut deps.storage, &bb, &a).unwrap(); + set_ref(&mut deps.storage, &a, &a).unwrap_err(); + + let chains = ref_chains(&deps.storage, &b, Some(5)).unwrap(); + + assert_eq!(chains, vec![a.clone()]); + + set_ref(&mut deps.storage, &c, &b).unwrap(); + set_ref(&mut deps.storage, &d, &c).unwrap(); + + let chains = ref_chains(&deps.storage, &d, Some(5)).unwrap(); + + assert_eq!(chains, vec![c.clone(), b.clone(), a.clone()]); + + let e = Addr::unchecked("e"); + let f = Addr::unchecked("f"); + let g = Addr::unchecked("g"); + + set_ref(&mut deps.storage, &e, &d).unwrap(); + set_ref(&mut deps.storage, &f, &e).unwrap(); + set_ref(&mut deps.storage, &g, &f).unwrap(); + + let chains = ref_chains(&deps.storage, &g, Some(5)).unwrap(); + + assert_eq!(chains, vec![f, e, d, c, b.clone()]); + assert_eq!(chains.len(), 5); + + let h = Addr::unchecked("h"); + let j = Addr::unchecked("j"); + set_ref(&mut deps.storage, &h, &a).unwrap(); + set_ref(&mut deps.storage, &j, &a).unwrap(); + + let all_ref_a = + all_referred_of(&deps.storage, a.clone(), None, None, None) + .unwrap(); + + assert_eq!(all_ref_a, vec![b.clone(), bb.clone(), h.clone(), j.clone()]); + + let all_ref_a = + all_referred_of(&deps.storage, a.clone(), Some(b.clone()), None, None) + .unwrap(); + + assert_eq!(all_ref_a, vec![bb.clone(), h.clone(), j.clone()]); + + let all_ref_a = + all_referred_of(&deps.storage, a.clone(), None, None, Some(false)) + .unwrap(); + + assert_eq!(all_ref_a, vec![j.clone(), h.clone(), bb.clone(), b.clone()]); + + let all_ref_a = + all_referred_of(&deps.storage, a.clone(), Some(j.clone()), None, Some(false)) + .unwrap(); + + assert_eq!(all_ref_a, vec![h.clone(), bb.clone(), b.clone()]); +} diff --git a/contracts/cw-cyber-gift/src/lib.rs b/contracts/cw-cyber-gift/src/lib.rs index c333bc9..8370d58 100644 --- a/contracts/cw-cyber-gift/src/lib.rs +++ b/contracts/cw-cyber-gift/src/lib.rs @@ -6,5 +6,6 @@ pub mod msg; pub mod state; pub mod query; mod tests; +pub mod indexed_referral; pub use crate::error::ContractError; diff --git a/contracts/cw-cyber-gift/src/msg.rs b/contracts/cw-cyber-gift/src/msg.rs index 080a111..95aac4c 100644 --- a/contracts/cw-cyber-gift/src/msg.rs +++ b/contracts/cw-cyber-gift/src/msg.rs @@ -1,7 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{CosmosMsg, Decimal, Uint128, Uint64}; +use cosmwasm_std::{Addr, CosmosMsg, Decimal, Uint128, Uint64}; use cw_utils::Expiration; use cyber_std::CyberMsgWrapper; @@ -43,6 +43,7 @@ pub enum ExecuteMsg { gift_amount: Uint128, /// Proof is hex-encoded merkle proof. proof: Vec, + referral: Option, }, Release { gift_address: String }, } @@ -57,7 +58,20 @@ pub enum QueryMsg { Claim { address: String }, ReleaseState { address: String }, ReleaseStageState { stage: u8 }, - AllReleaseStageStates{} + AllReleaseStageStates{}, + ReferralOf { address: String }, + HasReferral { address: String }, + AllReferrals { + start_after: Option, + limit: Option, + is_ascending: Option, + }, + AllReferredOf { + address: Addr, + start_after: Option, + limit: Option, + is_ascending: Option, + } } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] diff --git a/contracts/cw-cyber-gift/src/state.rs b/contracts/cw-cyber-gift/src/state.rs index 1b086a6..d417c96 100644 --- a/contracts/cw-cyber-gift/src/state.rs +++ b/contracts/cw-cyber-gift/src/state.rs @@ -40,6 +40,12 @@ pub struct ClaimState { pub multiplier: Decimal, } +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Refer { + pub referrer: Addr, + pub referred: Addr, +} + pub const CONFIG_KEY: &str = "config"; pub const CONFIG: Item = Item::new(CONFIG_KEY); @@ -57,3 +63,5 @@ pub const RELEASE: Map = Map::new(RELEASE_PREFIX); pub const RELEASES_STATS_PREFIX: &str = "releases_stats"; pub const RELEASES_STATS: Map = Map::new(RELEASES_STATS_PREFIX); + +pub const REFERRALS_PREFIX: &str = "referrals"; diff --git a/contracts/cw-cyber-gift/src/tests.rs b/contracts/cw-cyber-gift/src/tests.rs index 1cb4d97..613d0c1 100644 --- a/contracts/cw-cyber-gift/src/tests.rs +++ b/contracts/cw-cyber-gift/src/tests.rs @@ -1,6 +1,7 @@ #[cfg(test)] mod tests { use std::borrow::BorrowMut; + use std::cell::Ref; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; use cosmwasm_std::{attr, from_binary, Binary, Coin, Uint128, Uint64, Empty, Addr, coins}; use crate::msg::{AllReleaseStageStateResponse, ConfigResponse, ExecuteMsg, InstantiateMsg, MerkleRootResponse, QueryMsg}; @@ -12,6 +13,7 @@ mod tests { use cyber_std_test::CyberApp; use csv; use serde::Deserialize; + use crate::state::Refer; const NATIVE_TOKEN: &str = "boot"; const OWNER: &str = "owner"; @@ -258,7 +260,7 @@ mod tests { ); } - fn claim_and_release(app: &mut CyberApp, gift_addr: &Addr, treasury_addr: &Addr, data: &Vec, a: usize, b: usize, c: usize, d: usize) { + fn claim_and_release(app: &mut CyberApp, gift_addr: &Addr, treasury_addr: &Addr, data: &Vec, a: usize, b: usize, c: usize, d: usize, referral: Option) { for i in a..b { let _ =app.execute_contract( Addr::unchecked(data[i].bostrom_address.clone()), @@ -267,7 +269,8 @@ mod tests { nickname: data[i].nickname.clone(), gift_claiming_address: data[i].cosmos_address.clone(), gift_amount: Uint128::from(data[i].amount.clone()), - proof: data[i].cosmos_proof_vec() + proof: data[i].cosmos_proof_vec(), + referral: referral.clone(), }, &[], ); @@ -278,7 +281,8 @@ mod tests { nickname: data[i].nickname.clone(), gift_claiming_address: data[i].ethereum_address.clone(), gift_amount: Uint128::from(data[i].amount.clone()), - proof: data[i].ethereum_proof_vec() + proof: data[i].ethereum_proof_vec(), + referral: referral.clone(), }, &[], ); @@ -325,15 +329,32 @@ mod tests { println!("RELEASES - {:?}", "-------------"); } - claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 0, 5, 0, 5); - claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 5, 10, 0, 10); - claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 10, 15, 0, 15); - claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 15, 19, 0, 19); - claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 19, 20, 0, 20); + claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 0, 5, 0, 5, Some(String::from("bob"))); + claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 5, 10, 0, 10, Some(String::from("bob"))); + claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 10, 15, 0, 15, None); + claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 15, 19, 0, 19, None); + claim_and_release(app.borrow_mut(), &gift_addr, &treasury_addr, &data, 19, 20, 0, 20, None); for i in 0..20 { println!("PASSPORT #{:?} BAL- {:?}", i, app.wrap().query_balance(&Addr::unchecked(data[i].bostrom_address.clone()), "boot").unwrap()); } + + let rel: Vec = app.wrap().query_wasm_smart(gift_addr.clone(), &QueryMsg::AllReferrals { + start_after: None, + limit: None, + is_ascending: None + }).unwrap(); + println!("ALL REFERRALS - {:?}", rel.len()); + + let rel: Vec = app.wrap().query_wasm_smart(gift_addr.clone(), &QueryMsg::AllReferredOf { + address: Addr::unchecked(String::from("bob")), + start_after: None, + limit: None, + is_ascending: None + }).unwrap(); + println!("REFERRALS BOB - {:?}", rel.len()); + println!("REFERRAL BOB BAL - {:?}", app.wrap().query_balance("bob", "boot").unwrap()); + println!("COMMUNITY POOL BAL - {:?}", app.wrap().query_balance("alice", "boot").unwrap()); } #[test]