From d4f4c5bac5c21f0a77263fee28a5ca5e417a0c08 Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Thu, 7 Nov 2024 13:28:32 +0100 Subject: [PATCH 01/14] feat: factory msg and state to the package --- .../factory/src/bin/drop-factory-schema.rs | 2 +- contracts/factory/src/contract.rs | 20 +- contracts/factory/src/lib.rs | 2 - contracts/factory/src/tests.rs | 30 +- .../base/src/msg/factory.rs | 14 +- packages/base/src/msg/mod.rs | 1 + .../base/src/state/factory.rs | 2 +- packages/base/src/state/mod.rs | 1 + ts-client/lib/contractLib/dropStaker.d.ts | 203 ------------- ts-client/lib/contractLib/dropStaker.js | 78 ----- .../lib/contractLib/dropTokenDistributor.d.ts | 120 -------- .../lib/contractLib/dropTokenDistributor.js | 54 ---- .../lib/contractLib/tokenDistributor.d.ts | 120 -------- ts-client/lib/contractLib/tokenDistributor.js | 54 ---- ts-client/src/contractLib/dropStaker.ts | 281 ------------------ .../src/contractLib/dropTokenDistributor.ts | 182 ------------ ts-client/src/contractLib/tokenDistributor.ts | 182 ------------ 17 files changed, 36 insertions(+), 1310 deletions(-) rename contracts/factory/src/msg.rs => packages/base/src/msg/factory.rs (82%) rename contracts/factory/src/state.rs => packages/base/src/state/factory.rs (96%) delete mode 100644 ts-client/lib/contractLib/dropStaker.d.ts delete mode 100644 ts-client/lib/contractLib/dropStaker.js delete mode 100644 ts-client/lib/contractLib/dropTokenDistributor.d.ts delete mode 100644 ts-client/lib/contractLib/dropTokenDistributor.js delete mode 100644 ts-client/lib/contractLib/tokenDistributor.d.ts delete mode 100644 ts-client/lib/contractLib/tokenDistributor.js delete mode 100644 ts-client/src/contractLib/dropStaker.ts delete mode 100644 ts-client/src/contractLib/dropTokenDistributor.ts delete mode 100644 ts-client/src/contractLib/tokenDistributor.ts diff --git a/contracts/factory/src/bin/drop-factory-schema.rs b/contracts/factory/src/bin/drop-factory-schema.rs index 5e026829..ed4e59a0 100644 --- a/contracts/factory/src/bin/drop-factory-schema.rs +++ b/contracts/factory/src/bin/drop-factory-schema.rs @@ -1,5 +1,5 @@ use cosmwasm_schema::write_api; -use drop_factory::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; +use drop_staking_base::msg::factory::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; fn main() { write_api! { diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 451a01d2..78019227 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -1,17 +1,17 @@ -use crate::{ - error::ContractResult, - msg::{ - ExecuteMsg, InstantiateMsg, MigrateMsg, ProxyMsg, QueryMsg, UpdateConfigMsg, - ValidatorSetMsg, - }, - state::{State, STATE}, -}; +use crate::error::ContractResult; use cosmwasm_std::{ attr, instantiate2_address, to_json_binary, Binary, CodeInfoResponse, CosmosMsg, Deps, DepsMut, Env, HexBinary, MessageInfo, Response, StdResult, Uint128, WasmMsg, }; use drop_helpers::answer::response; use drop_staking_base::state::splitter::Config as SplitterConfig; +use drop_staking_base::{ + msg::factory::{ + ExecuteMsg, InstantiateMsg, MigrateMsg, ProxyMsg, QueryMsg, UpdateConfigMsg, + ValidatorSetMsg, + }, + state::factory::{State, STATE}, +}; use drop_staking_base::{ msg::{ core::{InstantiateMsg as CoreInstantiateMsg, QueryMsg as CoreQueryMsg}, @@ -462,7 +462,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult) -> StdResult { let state = STATE.load(deps.storage)?; - to_json_binary(&crate::state::PauseInfoResponse { + to_json_binary(&drop_staking_base::state::factory::PauseInfoResponse { core: deps .querier .query_wasm_smart(state.core_contract, &CoreQueryMsg::Pause {})?, @@ -670,7 +670,7 @@ pub fn migrate( } fn get_splitter_receivers( - fee_params: Option, + fee_params: Option, bond_provider_address: String, ) -> ContractResult> { match fee_params { diff --git a/contracts/factory/src/lib.rs b/contracts/factory/src/lib.rs index ce584245..19b07e61 100644 --- a/contracts/factory/src/lib.rs +++ b/contracts/factory/src/lib.rs @@ -1,6 +1,4 @@ pub mod contract; pub mod error; -pub mod msg; -pub mod state; #[cfg(test)] pub mod tests; diff --git a/contracts/factory/src/tests.rs b/contracts/factory/src/tests.rs index 780bafe5..d8f02027 100644 --- a/contracts/factory/src/tests.rs +++ b/contracts/factory/src/tests.rs @@ -1,17 +1,17 @@ -use crate::{ - contract::{execute, instantiate, query}, - msg::{ - CoreParams, ExecuteMsg, FeeParams, InstantiateMsg, LsmShareBondParams, NativeBondParams, - QueryMsg, UpdateConfigMsg, ValidatorSetMsg, - }, - state::{CodeIds, RemoteOpts, State, Timeout, STATE}, -}; +use crate::contract::{execute, instantiate, query}; use cosmwasm_std::{ attr, from_json, testing::{mock_env, mock_info}, to_json_binary, BankMsg, Uint128, }; use drop_helpers::testing::{mock_dependencies, mock_dependencies_with_api}; +use drop_staking_base::{ + msg::factory::{ + CoreParams, ExecuteMsg, FeeParams, InstantiateMsg, LsmShareBondParams, NativeBondParams, + QueryMsg, UpdateConfigMsg, ValidatorSetMsg, + }, + state::factory::{CodeIds, RemoteOpts, State, Timeout, STATE}, +}; use drop_staking_base::{ msg::{ core::{ExecuteMsg as CoreExecuteMsg, InstantiateMsg as CoreInstantiateMsg}, @@ -707,7 +707,7 @@ fn test_proxy_validators_set_update_validators_unauthorized() { deps.as_mut().into_empty(), mock_env(), mock_info("not_an_owner", &[]), - ExecuteMsg::Proxy(crate::msg::ProxyMsg::ValidatorSet( + ExecuteMsg::Proxy(drop_staking_base::msg::factory::ProxyMsg::ValidatorSet( ValidatorSetMsg::UpdateValidators { validators: vec![ drop_staking_base::msg::validatorset::ValidatorData { @@ -744,7 +744,7 @@ fn test_proxy_validators_set_update_validators() { deps.as_mut().into_empty(), mock_env(), mock_info("owner", &[]), - ExecuteMsg::Proxy(crate::msg::ProxyMsg::ValidatorSet( + ExecuteMsg::Proxy(drop_staking_base::msg::factory::ProxyMsg::ValidatorSet( ValidatorSetMsg::UpdateValidators { validators: vec![ drop_staking_base::msg::validatorset::ValidatorData { @@ -1091,7 +1091,7 @@ fn test_query_state() { STATE .save(deps.as_mut().storage, &get_default_factory_state()) .unwrap(); - let query_res: crate::state::State = + let query_res: drop_staking_base::state::factory::State = from_json(query(deps.as_ref(), mock_env(), QueryMsg::State {}).unwrap()).unwrap(); assert_eq!(query_res, get_default_factory_state()); } @@ -1121,11 +1121,11 @@ fn test_query_pause_info() { STATE .save(deps.as_mut().storage, &get_default_factory_state()) .unwrap(); - let query_res: crate::state::PauseInfoResponse = + let query_res: drop_staking_base::state::factory::PauseInfoResponse = from_json(query(deps.as_ref(), mock_env(), QueryMsg::PauseInfo {}).unwrap()).unwrap(); assert_eq!( query_res, - crate::state::PauseInfoResponse { + drop_staking_base::state::factory::PauseInfoResponse { core: CorePause { tick: true, bond: false, @@ -1146,7 +1146,7 @@ fn test_query_ownership() { query( deps.as_ref(), mock_env(), - crate::msg::QueryMsg::Ownership {}, + drop_staking_base::msg::factory::QueryMsg::Ownership {}, ) .unwrap(), ) @@ -1187,7 +1187,7 @@ fn test_transfer_ownership() { query( deps.as_ref(), mock_env(), - crate::msg::QueryMsg::Ownership {}, + drop_staking_base::msg::factory::QueryMsg::Ownership {}, ) .unwrap(), ) diff --git a/contracts/factory/src/msg.rs b/packages/base/src/msg/factory.rs similarity index 82% rename from contracts/factory/src/msg.rs rename to packages/base/src/msg/factory.rs index 2b82588d..9661d19d 100644 --- a/contracts/factory/src/msg.rs +++ b/packages/base/src/msg/factory.rs @@ -1,9 +1,9 @@ -use crate::state::{CodeIds, RemoteOpts}; +use crate::msg::token::DenomMetadata; +use crate::state::factory::{CodeIds, RemoteOpts}; use cosmwasm_schema::{cw_serde, QueryResponses}; use cosmwasm_std::{CosmosMsg, Decimal, Uint128}; use cw_ownable::cw_ownable_execute; use drop_macros::pausable; -use drop_staking_base::msg::token::DenomMetadata; use neutron_sdk::bindings::msg::NeutronMsg; #[cw_serde] @@ -53,8 +53,8 @@ pub struct LsmShareBondParams { #[cw_serde] pub enum UpdateConfigMsg { - Core(Box), - ValidatorsSet(drop_staking_base::state::validatorset::ConfigOptional), + Core(Box), + ValidatorsSet(crate::state::validatorset::ConfigOptional), } #[cw_serde] @@ -65,7 +65,7 @@ pub enum ProxyMsg { #[cw_serde] pub enum ValidatorSetMsg { UpdateValidators { - validators: Vec, + validators: Vec, }, } @@ -84,8 +84,8 @@ pub struct MigrateMsg {} #[cw_serde] #[derive(QueryResponses)] pub enum QueryMsg { - #[returns(crate::state::State)] + #[returns(crate::state::factory::State)] State {}, - #[returns(crate::state::PauseInfoResponse)] + #[returns(crate::state::factory::PauseInfoResponse)] PauseInfo {}, } diff --git a/packages/base/src/msg/mod.rs b/packages/base/src/msg/mod.rs index b4e1197d..7eca191e 100644 --- a/packages/base/src/msg/mod.rs +++ b/packages/base/src/msg/mod.rs @@ -2,6 +2,7 @@ pub mod astroport_exchange_handler; pub mod bond_provider; pub mod core; pub mod distribution; +pub mod factory; pub mod hook_tester; pub mod lsm_share_bond_provider; pub mod mirror; diff --git a/contracts/factory/src/state.rs b/packages/base/src/state/factory.rs similarity index 96% rename from contracts/factory/src/state.rs rename to packages/base/src/state/factory.rs index 21755c81..9e759cd8 100644 --- a/contracts/factory/src/state.rs +++ b/packages/base/src/state/factory.rs @@ -55,7 +55,7 @@ pub struct State { #[cw_serde] pub struct PauseInfoResponse { pub withdrawal_manager: drop_helpers::pause::PauseInfoResponse, - pub core: drop_staking_base::state::core::Pause, + pub core: crate::state::core::Pause, pub rewards_manager: drop_helpers::pause::PauseInfoResponse, } diff --git a/packages/base/src/state/mod.rs b/packages/base/src/state/mod.rs index 3170f923..057f7a99 100644 --- a/packages/base/src/state/mod.rs +++ b/packages/base/src/state/mod.rs @@ -1,6 +1,7 @@ pub mod astroport_exchange_handler; pub mod bond_providers; pub mod core; +pub mod factory; pub mod hook_tester; pub mod lsm_share_bond_provider; pub mod mirror; diff --git a/ts-client/lib/contractLib/dropStaker.d.ts b/ts-client/lib/contractLib/dropStaker.d.ts deleted file mode 100644 index c60ecdc6..00000000 --- a/ts-client/lib/contractLib/dropStaker.d.ts +++ /dev/null @@ -1,203 +0,0 @@ -import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult, InstantiateResult } from "@cosmjs/cosmwasm-stargate"; -import { StdFee } from "@cosmjs/amino"; -import { Coin } from "@cosmjs/amino"; -/** - * A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq. - * - * # Examples - * - * Use `from` to create instances of this and `u128` to get the value out: - * - * ``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123); - * - * let b = Uint128::from(42u64); assert_eq!(b.u128(), 42); - * - * let c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ``` - */ -export type Uint128 = string; -/** - * A human readable address. - * - * In Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length. - * - * This type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances. - * - * This type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance. - */ -export type Addr = string; -export type IcaState = ("none" | "in_progress" | "timeout") | { - registered: { - channel_id: string; - ica_address: string; - port_id: string; - }; -}; -/** - * A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq. - * - * # Examples - * - * Use `from` to create instances of this and `u128` to get the value out: - * - * ``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123); - * - * let b = Uint128::from(42u64); assert_eq!(b.u128(), 42); - * - * let c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ``` - */ -export type Uint1281 = string; -/** - * Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future) - */ -export type Expiration = { - at_height: number; -} | { - at_time: Timestamp; -} | { - never: {}; -}; -/** - * A point in time in nanosecond precision. - * - * This type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z. - * - * ## Examples - * - * ``` # 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); - * - * let ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ``` - */ -export type Timestamp = Uint64; -/** - * 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. - * - * # Examples - * - * Use `from` to create instances of this and `u64` to get the value out: - * - * ``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42); - * - * let b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ``` - */ -export type Uint64 = string; -export type TxStateStatus = "idle" | "in_progress" | "waiting_for_ack"; -export type Transaction = { - stake: { - amount: Uint1282; - }; -} | { - i_b_c_transfer: { - amount: Uint1282; - }; -}; -/** - * A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq. - * - * # Examples - * - * Use `from` to create instances of this and `u128` to get the value out: - * - * ``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123); - * - * let b = Uint128::from(42u64); assert_eq!(b.u128(), 42); - * - * let c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ``` - */ -export type Uint1282 = string; -/** - * Actions that can be taken to alter the contract's ownership - */ -export type UpdateOwnershipArgs = { - transfer_ownership: { - expiry?: Expiration | null; - new_owner: string; - }; -} | "accept_ownership" | "renounce_ownership"; -export type ChainType = "basic_cosmos" | "initia"; -export interface DropStakerSchema { - responses: Uint128 | Config | IcaState | Uint1281 | OwnershipForString | TxState; - execute: StakeArgs | UpdateConfigArgs | UpdateOwnershipArgs; - instantiate?: InstantiateMsg; - [k: string]: unknown; -} -export interface Config { - connection_id: string; - dest_address?: Addr | null; - dest_channel?: string | null; - dest_port?: string | null; - local_denom: string; - refundee?: Addr | null; - timeout: PumpTimeout; -} -export interface PumpTimeout { - local?: number | null; - remote: number; -} -/** - * The contract's ownership info - */ -export interface OwnershipForString { - /** - * The contract's current owner. `None` if the ownership has been renounced. - */ - owner?: string | null; - /** - * The deadline for the pending owner to accept the ownership. `None` if there isn't a pending ownership transfer, or if a transfer exists and it doesn't have a deadline. - */ - pending_expiry?: Expiration | null; - /** - * The account who has been proposed to take over the ownership. `None` if there isn't a pending ownership transfer. - */ - pending_owner?: string | null; -} -export interface TxState { - reply_to?: string | null; - seq_id?: number | null; - status: TxStateStatus; - transaction?: Transaction | null; -} -export interface StakeArgs { - items: [string, Uint1282][]; -} -export interface UpdateConfigArgs { - new_config: ConfigOptional; -} -export interface ConfigOptional { - allowed_senders?: string[] | null; - min_ibc_transfer?: Uint1282 | null; - min_staking_amount?: Uint1282 | null; - puppeteer_ica?: string | null; - timeout?: number | null; -} -export interface InstantiateMsg { - allowed_senders: string[]; - base_denom: string; - chain_type?: ChainType | null; - connection_id: string; - min_ibc_transfer: Uint1282; - min_staking_amount: Uint1282; - owner?: string | null; - port_id: string; - remote_denom: string; - timeout: number; - transfer_channel_id: string; -} -export declare class Client { - private readonly client; - contractAddress: string; - constructor(client: CosmWasmClient | SigningCosmWasmClient, contractAddress: string); - mustBeSigningClient(): Error; - static instantiate(client: SigningCosmWasmClient, sender: string, codeId: number, initMsg: InstantiateMsg, label: string, fees: StdFee | 'auto' | number, initCoins?: readonly Coin[]): Promise; - static instantiate2(client: SigningCosmWasmClient, sender: string, codeId: number, salt: number, initMsg: InstantiateMsg, label: string, fees: StdFee | 'auto' | number, initCoins?: readonly Coin[]): Promise; - queryConfig: () => Promise; - queryNonStakedBalance: () => Promise; - queryAllBalance: () => Promise; - queryIca: () => Promise; - queryTxState: () => Promise; - queryOwnership: () => Promise; - registerICA: (sender: string, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => Promise; - stake: (sender: string, args: StakeArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => Promise; - iBCTransfer: (sender: string, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => Promise; - updateConfig: (sender: string, args: UpdateConfigArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => Promise; - updateOwnership: (sender: string, args: UpdateOwnershipArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => Promise; -} diff --git a/ts-client/lib/contractLib/dropStaker.js b/ts-client/lib/contractLib/dropStaker.js deleted file mode 100644 index 0d2fbf70..00000000 --- a/ts-client/lib/contractLib/dropStaker.js +++ /dev/null @@ -1,78 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.Client = void 0; -function isSigningCosmWasmClient(client) { - return 'execute' in client; -} -class Client { - client; - contractAddress; - constructor(client, contractAddress) { - this.client = client; - this.contractAddress = contractAddress; - } - mustBeSigningClient() { - return new Error("This client is not a SigningCosmWasmClient"); - } - static async instantiate(client, sender, codeId, initMsg, label, fees, initCoins) { - const res = await client.instantiate(sender, codeId, initMsg, label, fees, { - ...(initCoins && initCoins.length && { funds: initCoins }), - }); - return res; - } - static async instantiate2(client, sender, codeId, salt, initMsg, label, fees, initCoins) { - const res = await client.instantiate2(sender, codeId, new Uint8Array([salt]), initMsg, label, fees, { - ...(initCoins && initCoins.length && { funds: initCoins }), - }); - return res; - } - queryConfig = async () => { - return this.client.queryContractSmart(this.contractAddress, { config: {} }); - }; - queryNonStakedBalance = async () => { - return this.client.queryContractSmart(this.contractAddress, { non_staked_balance: {} }); - }; - queryAllBalance = async () => { - return this.client.queryContractSmart(this.contractAddress, { all_balance: {} }); - }; - queryIca = async () => { - return this.client.queryContractSmart(this.contractAddress, { ica: {} }); - }; - queryTxState = async () => { - return this.client.queryContractSmart(this.contractAddress, { tx_state: {} }); - }; - queryOwnership = async () => { - return this.client.queryContractSmart(this.contractAddress, { ownership: {} }); - }; - registerICA = async (sender, fee, memo, funds) => { - if (!isSigningCosmWasmClient(this.client)) { - throw this.mustBeSigningClient(); - } - return this.client.execute(sender, this.contractAddress, { register_i_c_a: {} }, fee || "auto", memo, funds); - }; - stake = async (sender, args, fee, memo, funds) => { - if (!isSigningCosmWasmClient(this.client)) { - throw this.mustBeSigningClient(); - } - return this.client.execute(sender, this.contractAddress, { stake: args }, fee || "auto", memo, funds); - }; - iBCTransfer = async (sender, fee, memo, funds) => { - if (!isSigningCosmWasmClient(this.client)) { - throw this.mustBeSigningClient(); - } - return this.client.execute(sender, this.contractAddress, { i_b_c_transfer: {} }, fee || "auto", memo, funds); - }; - updateConfig = async (sender, args, fee, memo, funds) => { - if (!isSigningCosmWasmClient(this.client)) { - throw this.mustBeSigningClient(); - } - return this.client.execute(sender, this.contractAddress, { update_config: args }, fee || "auto", memo, funds); - }; - updateOwnership = async (sender, args, fee, memo, funds) => { - if (!isSigningCosmWasmClient(this.client)) { - throw this.mustBeSigningClient(); - } - return this.client.execute(sender, this.contractAddress, { update_ownership: args }, fee || "auto", memo, funds); - }; -} -exports.Client = Client; diff --git a/ts-client/lib/contractLib/dropTokenDistributor.d.ts b/ts-client/lib/contractLib/dropTokenDistributor.d.ts deleted file mode 100644 index 82feca91..00000000 --- a/ts-client/lib/contractLib/dropTokenDistributor.d.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult, InstantiateResult } from "@cosmjs/cosmwasm-stargate"; -import { StdFee } from "@cosmjs/amino"; -import { Coin } from "@cosmjs/amino"; -/** - * A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq. - * - * # Examples - * - * Use `from` to create instances of this and `u128` to get the value out: - * - * ``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123); - * - * let b = Uint128::from(42u64); assert_eq!(b.u128(), 42); - * - * let c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ``` - */ -export type Uint128 = string; -/** - * Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future) - */ -export type Expiration = { - at_height: number; -} | { - at_time: Timestamp; -} | { - never: {}; -}; -/** - * A point in time in nanosecond precision. - * - * This type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z. - * - * ## Examples - * - * ``` # 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); - * - * let ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ``` - */ -export type Timestamp = Uint64; -/** - * 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. - * - * # Examples - * - * Use `from` to create instances of this and `u64` to get the value out: - * - * ``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42); - * - * let b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ``` - */ -export type Uint64 = string; -export type Token = { - native: { - denom: string; - }; -} | { - c_w20: { - address: string; - }; -}; -/** - * Actions that can be taken to alter the contract's ownership - */ -export type UpdateOwnershipArgs = { - transfer_ownership: { - expiry?: Expiration | null; - new_owner: string; - }; -} | "accept_ownership" | "renounce_ownership"; -export interface DropTokenDistributorSchema { - responses: Config | OwnershipForString; - execute: DistributeArgs | UpdateConfigArgs | UpdateOwnershipArgs; - instantiate?: InstantiateMsg; - [k: string]: unknown; -} -export interface Config { - receivers: [string, Uint128][]; -} -/** - * The contract's ownership info - */ -export interface OwnershipForString { - /** - * The contract's current owner. `None` if the ownership has been renounced. - */ - owner?: string | null; - /** - * The deadline for the pending owner to accept the ownership. `None` if there isn't a pending ownership transfer, or if a transfer exists and it doesn't have a deadline. - */ - pending_expiry?: Expiration | null; - /** - * The account who has been proposed to take over the ownership. `None` if there isn't a pending ownership transfer. - */ - pending_owner?: string | null; -} -export interface DistributeArgs { - denoms: Token[]; -} -export interface UpdateConfigArgs { - new_config: Config1; -} -export interface Config1 { - receivers: [string, Uint128][]; -} -export interface InstantiateMsg { - config: Config1; -} -export declare class Client { - private readonly client; - contractAddress: string; - constructor(client: CosmWasmClient | SigningCosmWasmClient, contractAddress: string); - mustBeSigningClient(): Error; - static instantiate(client: SigningCosmWasmClient, sender: string, codeId: number, initMsg: InstantiateMsg, label: string, fees: StdFee | 'auto' | number, initCoins?: readonly Coin[]): Promise; - static instantiate2(client: SigningCosmWasmClient, sender: string, codeId: number, salt: number, initMsg: InstantiateMsg, label: string, fees: StdFee | 'auto' | number, initCoins?: readonly Coin[]): Promise; - queryConfig: () => Promise; - queryOwnership: () => Promise; - distribute: (sender: string, args: DistributeArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => Promise; - updateConfig: (sender: string, args: UpdateConfigArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => Promise; - updateOwnership: (sender: string, args: UpdateOwnershipArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => Promise; -} diff --git a/ts-client/lib/contractLib/dropTokenDistributor.js b/ts-client/lib/contractLib/dropTokenDistributor.js deleted file mode 100644 index 03e691fe..00000000 --- a/ts-client/lib/contractLib/dropTokenDistributor.js +++ /dev/null @@ -1,54 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.Client = void 0; -function isSigningCosmWasmClient(client) { - return 'execute' in client; -} -class Client { - client; - contractAddress; - constructor(client, contractAddress) { - this.client = client; - this.contractAddress = contractAddress; - } - mustBeSigningClient() { - return new Error("This client is not a SigningCosmWasmClient"); - } - static async instantiate(client, sender, codeId, initMsg, label, fees, initCoins) { - const res = await client.instantiate(sender, codeId, initMsg, label, fees, { - ...(initCoins && initCoins.length && { funds: initCoins }), - }); - return res; - } - static async instantiate2(client, sender, codeId, salt, initMsg, label, fees, initCoins) { - const res = await client.instantiate2(sender, codeId, new Uint8Array([salt]), initMsg, label, fees, { - ...(initCoins && initCoins.length && { funds: initCoins }), - }); - return res; - } - queryConfig = async () => { - return this.client.queryContractSmart(this.contractAddress, { config: {} }); - }; - queryOwnership = async () => { - return this.client.queryContractSmart(this.contractAddress, { ownership: {} }); - }; - distribute = async (sender, args, fee, memo, funds) => { - if (!isSigningCosmWasmClient(this.client)) { - throw this.mustBeSigningClient(); - } - return this.client.execute(sender, this.contractAddress, { distribute: args }, fee || "auto", memo, funds); - }; - updateConfig = async (sender, args, fee, memo, funds) => { - if (!isSigningCosmWasmClient(this.client)) { - throw this.mustBeSigningClient(); - } - return this.client.execute(sender, this.contractAddress, { update_config: args }, fee || "auto", memo, funds); - }; - updateOwnership = async (sender, args, fee, memo, funds) => { - if (!isSigningCosmWasmClient(this.client)) { - throw this.mustBeSigningClient(); - } - return this.client.execute(sender, this.contractAddress, { update_ownership: args }, fee || "auto", memo, funds); - }; -} -exports.Client = Client; diff --git a/ts-client/lib/contractLib/tokenDistributor.d.ts b/ts-client/lib/contractLib/tokenDistributor.d.ts deleted file mode 100644 index 0edafb6a..00000000 --- a/ts-client/lib/contractLib/tokenDistributor.d.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult, InstantiateResult } from "@cosmjs/cosmwasm-stargate"; -import { StdFee } from "@cosmjs/amino"; -import { Coin } from "@cosmjs/amino"; -/** - * A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq. - * - * # Examples - * - * Use `from` to create instances of this and `u128` to get the value out: - * - * ``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123); - * - * let b = Uint128::from(42u64); assert_eq!(b.u128(), 42); - * - * let c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ``` - */ -export type Uint128 = string; -/** - * Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future) - */ -export type Expiration = { - at_height: number; -} | { - at_time: Timestamp; -} | { - never: {}; -}; -/** - * A point in time in nanosecond precision. - * - * This type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z. - * - * ## Examples - * - * ``` # 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); - * - * let ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ``` - */ -export type Timestamp = Uint64; -/** - * 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. - * - * # Examples - * - * Use `from` to create instances of this and `u64` to get the value out: - * - * ``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42); - * - * let b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ``` - */ -export type Uint64 = string; -export type Token = { - native: { - denom: string; - }; -} | { - c_w20: { - address: string; - }; -}; -/** - * Actions that can be taken to alter the contract's ownership - */ -export type UpdateOwnershipArgs = { - transfer_ownership: { - expiry?: Expiration | null; - new_owner: string; - }; -} | "accept_ownership" | "renounce_ownership"; -export interface TokenDistributorSchema { - responses: Config | OwnershipForString; - execute: DistributeArgs | UpdateConfigArgs | UpdateOwnershipArgs; - instantiate?: InstantiateMsg; - [k: string]: unknown; -} -export interface Config { - receivers: [string, Uint128][]; -} -/** - * The contract's ownership info - */ -export interface OwnershipForString { - /** - * The contract's current owner. `None` if the ownership has been renounced. - */ - owner?: string | null; - /** - * The deadline for the pending owner to accept the ownership. `None` if there isn't a pending ownership transfer, or if a transfer exists and it doesn't have a deadline. - */ - pending_expiry?: Expiration | null; - /** - * The account who has been proposed to take over the ownership. `None` if there isn't a pending ownership transfer. - */ - pending_owner?: string | null; -} -export interface DistributeArgs { - denoms: Token[]; -} -export interface UpdateConfigArgs { - new_config: Config1; -} -export interface Config1 { - receivers: [string, Uint128][]; -} -export interface InstantiateMsg { - config: Config1; -} -export declare class Client { - private readonly client; - contractAddress: string; - constructor(client: CosmWasmClient | SigningCosmWasmClient, contractAddress: string); - mustBeSigningClient(): Error; - static instantiate(client: SigningCosmWasmClient, sender: string, codeId: number, initMsg: InstantiateMsg, label: string, fees: StdFee | 'auto' | number, initCoins?: readonly Coin[]): Promise; - static instantiate2(client: SigningCosmWasmClient, sender: string, codeId: number, salt: number, initMsg: InstantiateMsg, label: string, fees: StdFee | 'auto' | number, initCoins?: readonly Coin[]): Promise; - queryConfig: () => Promise; - queryOwnership: () => Promise; - distribute: (sender: string, args: DistributeArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => Promise; - updateConfig: (sender: string, args: UpdateConfigArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => Promise; - updateOwnership: (sender: string, args: UpdateOwnershipArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => Promise; -} diff --git a/ts-client/lib/contractLib/tokenDistributor.js b/ts-client/lib/contractLib/tokenDistributor.js deleted file mode 100644 index 03e691fe..00000000 --- a/ts-client/lib/contractLib/tokenDistributor.js +++ /dev/null @@ -1,54 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.Client = void 0; -function isSigningCosmWasmClient(client) { - return 'execute' in client; -} -class Client { - client; - contractAddress; - constructor(client, contractAddress) { - this.client = client; - this.contractAddress = contractAddress; - } - mustBeSigningClient() { - return new Error("This client is not a SigningCosmWasmClient"); - } - static async instantiate(client, sender, codeId, initMsg, label, fees, initCoins) { - const res = await client.instantiate(sender, codeId, initMsg, label, fees, { - ...(initCoins && initCoins.length && { funds: initCoins }), - }); - return res; - } - static async instantiate2(client, sender, codeId, salt, initMsg, label, fees, initCoins) { - const res = await client.instantiate2(sender, codeId, new Uint8Array([salt]), initMsg, label, fees, { - ...(initCoins && initCoins.length && { funds: initCoins }), - }); - return res; - } - queryConfig = async () => { - return this.client.queryContractSmart(this.contractAddress, { config: {} }); - }; - queryOwnership = async () => { - return this.client.queryContractSmart(this.contractAddress, { ownership: {} }); - }; - distribute = async (sender, args, fee, memo, funds) => { - if (!isSigningCosmWasmClient(this.client)) { - throw this.mustBeSigningClient(); - } - return this.client.execute(sender, this.contractAddress, { distribute: args }, fee || "auto", memo, funds); - }; - updateConfig = async (sender, args, fee, memo, funds) => { - if (!isSigningCosmWasmClient(this.client)) { - throw this.mustBeSigningClient(); - } - return this.client.execute(sender, this.contractAddress, { update_config: args }, fee || "auto", memo, funds); - }; - updateOwnership = async (sender, args, fee, memo, funds) => { - if (!isSigningCosmWasmClient(this.client)) { - throw this.mustBeSigningClient(); - } - return this.client.execute(sender, this.contractAddress, { update_ownership: args }, fee || "auto", memo, funds); - }; -} -exports.Client = Client; diff --git a/ts-client/src/contractLib/dropStaker.ts b/ts-client/src/contractLib/dropStaker.ts deleted file mode 100644 index d7b5451e..00000000 --- a/ts-client/src/contractLib/dropStaker.ts +++ /dev/null @@ -1,281 +0,0 @@ -import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult, InstantiateResult } from "@cosmjs/cosmwasm-stargate"; -import { StdFee } from "@cosmjs/amino"; -import { Coin } from "@cosmjs/amino"; -/** - * A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq. - * - * # Examples - * - * Use `from` to create instances of this and `u128` to get the value out: - * - * ``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123); - * - * let b = Uint128::from(42u64); assert_eq!(b.u128(), 42); - * - * let c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ``` - */ -export type Uint128 = string; -/** - * A human readable address. - * - * In Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length. - * - * This type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances. - * - * This type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance. - */ -export type Addr = string; -export type IcaState = - | ("none" | "in_progress" | "timeout") - | { - registered: { - channel_id: string; - ica_address: string; - port_id: string; - }; - }; -/** - * A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq. - * - * # Examples - * - * Use `from` to create instances of this and `u128` to get the value out: - * - * ``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123); - * - * let b = Uint128::from(42u64); assert_eq!(b.u128(), 42); - * - * let c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ``` - */ -export type Uint1281 = string; -/** - * Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future) - */ -export type Expiration = - | { - at_height: number; - } - | { - at_time: Timestamp; - } - | { - never: {}; - }; -/** - * A point in time in nanosecond precision. - * - * This type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z. - * - * ## Examples - * - * ``` # 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); - * - * let ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ``` - */ -export type Timestamp = Uint64; -/** - * 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. - * - * # Examples - * - * Use `from` to create instances of this and `u64` to get the value out: - * - * ``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42); - * - * let b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ``` - */ -export type Uint64 = string; -export type TxStateStatus = "idle" | "in_progress" | "waiting_for_ack"; -export type Transaction = - | { - stake: { - amount: Uint1282; - }; - } - | { - i_b_c_transfer: { - amount: Uint1282; - }; - }; -/** - * A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq. - * - * # Examples - * - * Use `from` to create instances of this and `u128` to get the value out: - * - * ``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123); - * - * let b = Uint128::from(42u64); assert_eq!(b.u128(), 42); - * - * let c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ``` - */ -export type Uint1282 = string; -/** - * Actions that can be taken to alter the contract's ownership - */ -export type UpdateOwnershipArgs = - | { - transfer_ownership: { - expiry?: Expiration | null; - new_owner: string; - }; - } - | "accept_ownership" - | "renounce_ownership"; -export type ChainType = "basic_cosmos" | "initia"; - -export interface DropStakerSchema { - responses: Uint128 | Config | IcaState | Uint1281 | OwnershipForString | TxState; - execute: StakeArgs | UpdateConfigArgs | UpdateOwnershipArgs; - instantiate?: InstantiateMsg; - [k: string]: unknown; -} -export interface Config { - connection_id: string; - dest_address?: Addr | null; - dest_channel?: string | null; - dest_port?: string | null; - local_denom: string; - refundee?: Addr | null; - timeout: PumpTimeout; -} -export interface PumpTimeout { - local?: number | null; - remote: number; -} -/** - * The contract's ownership info - */ -export interface OwnershipForString { - /** - * The contract's current owner. `None` if the ownership has been renounced. - */ - owner?: string | null; - /** - * The deadline for the pending owner to accept the ownership. `None` if there isn't a pending ownership transfer, or if a transfer exists and it doesn't have a deadline. - */ - pending_expiry?: Expiration | null; - /** - * The account who has been proposed to take over the ownership. `None` if there isn't a pending ownership transfer. - */ - pending_owner?: string | null; -} -export interface TxState { - reply_to?: string | null; - seq_id?: number | null; - status: TxStateStatus; - transaction?: Transaction | null; -} -export interface StakeArgs { - items: [string, Uint1282][]; -} -export interface UpdateConfigArgs { - new_config: ConfigOptional; -} -export interface ConfigOptional { - allowed_senders?: string[] | null; - min_ibc_transfer?: Uint1282 | null; - min_staking_amount?: Uint1282 | null; - puppeteer_ica?: string | null; - timeout?: number | null; -} -export interface InstantiateMsg { - allowed_senders: string[]; - base_denom: string; - chain_type?: ChainType | null; - connection_id: string; - min_ibc_transfer: Uint1282; - min_staking_amount: Uint1282; - owner?: string | null; - port_id: string; - remote_denom: string; - timeout: number; - transfer_channel_id: string; -} - - -function isSigningCosmWasmClient( - client: CosmWasmClient | SigningCosmWasmClient -): client is SigningCosmWasmClient { - return 'execute' in client; -} - -export class Client { - private readonly client: CosmWasmClient | SigningCosmWasmClient; - contractAddress: string; - constructor(client: CosmWasmClient | SigningCosmWasmClient, contractAddress: string) { - this.client = client; - this.contractAddress = contractAddress; - } - mustBeSigningClient() { - return new Error("This client is not a SigningCosmWasmClient"); - } - static async instantiate( - client: SigningCosmWasmClient, - sender: string, - codeId: number, - initMsg: InstantiateMsg, - label: string, - fees: StdFee | 'auto' | number, - initCoins?: readonly Coin[], - ): Promise { - const res = await client.instantiate(sender, codeId, initMsg, label, fees, { - ...(initCoins && initCoins.length && { funds: initCoins }), - }); - return res; - } - static async instantiate2( - client: SigningCosmWasmClient, - sender: string, - codeId: number, - salt: number, - initMsg: InstantiateMsg, - label: string, - fees: StdFee | 'auto' | number, - initCoins?: readonly Coin[], - ): Promise { - const res = await client.instantiate2(sender, codeId, new Uint8Array([salt]), initMsg, label, fees, { - ...(initCoins && initCoins.length && { funds: initCoins }), - }); - return res; - } - queryConfig = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { config: {} }); - } - queryNonStakedBalance = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { non_staked_balance: {} }); - } - queryAllBalance = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { all_balance: {} }); - } - queryIca = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { ica: {} }); - } - queryTxState = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { tx_state: {} }); - } - queryOwnership = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { ownership: {} }); - } - registerICA = async(sender: string, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { register_i_c_a: {} }, fee || "auto", memo, funds); - } - stake = async(sender:string, args: StakeArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { stake: args }, fee || "auto", memo, funds); - } - iBCTransfer = async(sender: string, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { i_b_c_transfer: {} }, fee || "auto", memo, funds); - } - updateConfig = async(sender:string, args: UpdateConfigArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { update_config: args }, fee || "auto", memo, funds); - } - updateOwnership = async(sender:string, args: UpdateOwnershipArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { update_ownership: args }, fee || "auto", memo, funds); - } -} diff --git a/ts-client/src/contractLib/dropTokenDistributor.ts b/ts-client/src/contractLib/dropTokenDistributor.ts deleted file mode 100644 index 299a9ac6..00000000 --- a/ts-client/src/contractLib/dropTokenDistributor.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult, InstantiateResult } from "@cosmjs/cosmwasm-stargate"; -import { StdFee } from "@cosmjs/amino"; -import { Coin } from "@cosmjs/amino"; -/** - * A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq. - * - * # Examples - * - * Use `from` to create instances of this and `u128` to get the value out: - * - * ``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123); - * - * let b = Uint128::from(42u64); assert_eq!(b.u128(), 42); - * - * let c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ``` - */ -export type Uint128 = string; -/** - * Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future) - */ -export type Expiration = - | { - at_height: number; - } - | { - at_time: Timestamp; - } - | { - never: {}; - }; -/** - * A point in time in nanosecond precision. - * - * This type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z. - * - * ## Examples - * - * ``` # 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); - * - * let ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ``` - */ -export type Timestamp = Uint64; -/** - * 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. - * - * # Examples - * - * Use `from` to create instances of this and `u64` to get the value out: - * - * ``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42); - * - * let b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ``` - */ -export type Uint64 = string; -export type Token = - | { - native: { - denom: string; - }; - } - | { - c_w20: { - address: string; - }; - }; -/** - * Actions that can be taken to alter the contract's ownership - */ -export type UpdateOwnershipArgs = - | { - transfer_ownership: { - expiry?: Expiration | null; - new_owner: string; - }; - } - | "accept_ownership" - | "renounce_ownership"; - -export interface DropTokenDistributorSchema { - responses: Config | OwnershipForString; - execute: DistributeArgs | UpdateConfigArgs | UpdateOwnershipArgs; - instantiate?: InstantiateMsg; - [k: string]: unknown; -} -export interface Config { - receivers: [string, Uint128][]; -} -/** - * The contract's ownership info - */ -export interface OwnershipForString { - /** - * The contract's current owner. `None` if the ownership has been renounced. - */ - owner?: string | null; - /** - * The deadline for the pending owner to accept the ownership. `None` if there isn't a pending ownership transfer, or if a transfer exists and it doesn't have a deadline. - */ - pending_expiry?: Expiration | null; - /** - * The account who has been proposed to take over the ownership. `None` if there isn't a pending ownership transfer. - */ - pending_owner?: string | null; -} -export interface DistributeArgs { - denoms: Token[]; -} -export interface UpdateConfigArgs { - new_config: Config1; -} -export interface Config1 { - receivers: [string, Uint128][]; -} -export interface InstantiateMsg { - config: Config1; -} - - -function isSigningCosmWasmClient( - client: CosmWasmClient | SigningCosmWasmClient -): client is SigningCosmWasmClient { - return 'execute' in client; -} - -export class Client { - private readonly client: CosmWasmClient | SigningCosmWasmClient; - contractAddress: string; - constructor(client: CosmWasmClient | SigningCosmWasmClient, contractAddress: string) { - this.client = client; - this.contractAddress = contractAddress; - } - mustBeSigningClient() { - return new Error("This client is not a SigningCosmWasmClient"); - } - static async instantiate( - client: SigningCosmWasmClient, - sender: string, - codeId: number, - initMsg: InstantiateMsg, - label: string, - fees: StdFee | 'auto' | number, - initCoins?: readonly Coin[], - ): Promise { - const res = await client.instantiate(sender, codeId, initMsg, label, fees, { - ...(initCoins && initCoins.length && { funds: initCoins }), - }); - return res; - } - static async instantiate2( - client: SigningCosmWasmClient, - sender: string, - codeId: number, - salt: number, - initMsg: InstantiateMsg, - label: string, - fees: StdFee | 'auto' | number, - initCoins?: readonly Coin[], - ): Promise { - const res = await client.instantiate2(sender, codeId, new Uint8Array([salt]), initMsg, label, fees, { - ...(initCoins && initCoins.length && { funds: initCoins }), - }); - return res; - } - queryConfig = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { config: {} }); - } - queryOwnership = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { ownership: {} }); - } - distribute = async(sender:string, args: DistributeArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { distribute: args }, fee || "auto", memo, funds); - } - updateConfig = async(sender:string, args: UpdateConfigArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { update_config: args }, fee || "auto", memo, funds); - } - updateOwnership = async(sender:string, args: UpdateOwnershipArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { update_ownership: args }, fee || "auto", memo, funds); - } -} diff --git a/ts-client/src/contractLib/tokenDistributor.ts b/ts-client/src/contractLib/tokenDistributor.ts deleted file mode 100644 index daf93b63..00000000 --- a/ts-client/src/contractLib/tokenDistributor.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult, InstantiateResult } from "@cosmjs/cosmwasm-stargate"; -import { StdFee } from "@cosmjs/amino"; -import { Coin } from "@cosmjs/amino"; -/** - * A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq. - * - * # Examples - * - * Use `from` to create instances of this and `u128` to get the value out: - * - * ``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123); - * - * let b = Uint128::from(42u64); assert_eq!(b.u128(), 42); - * - * let c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ``` - */ -export type Uint128 = string; -/** - * Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future) - */ -export type Expiration = - | { - at_height: number; - } - | { - at_time: Timestamp; - } - | { - never: {}; - }; -/** - * A point in time in nanosecond precision. - * - * This type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z. - * - * ## Examples - * - * ``` # 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); - * - * let ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ``` - */ -export type Timestamp = Uint64; -/** - * 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. - * - * # Examples - * - * Use `from` to create instances of this and `u64` to get the value out: - * - * ``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42); - * - * let b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ``` - */ -export type Uint64 = string; -export type Token = - | { - native: { - denom: string; - }; - } - | { - c_w20: { - address: string; - }; - }; -/** - * Actions that can be taken to alter the contract's ownership - */ -export type UpdateOwnershipArgs = - | { - transfer_ownership: { - expiry?: Expiration | null; - new_owner: string; - }; - } - | "accept_ownership" - | "renounce_ownership"; - -export interface TokenDistributorSchema { - responses: Config | OwnershipForString; - execute: DistributeArgs | UpdateConfigArgs | UpdateOwnershipArgs; - instantiate?: InstantiateMsg; - [k: string]: unknown; -} -export interface Config { - receivers: [string, Uint128][]; -} -/** - * The contract's ownership info - */ -export interface OwnershipForString { - /** - * The contract's current owner. `None` if the ownership has been renounced. - */ - owner?: string | null; - /** - * The deadline for the pending owner to accept the ownership. `None` if there isn't a pending ownership transfer, or if a transfer exists and it doesn't have a deadline. - */ - pending_expiry?: Expiration | null; - /** - * The account who has been proposed to take over the ownership. `None` if there isn't a pending ownership transfer. - */ - pending_owner?: string | null; -} -export interface DistributeArgs { - denoms: Token[]; -} -export interface UpdateConfigArgs { - new_config: Config1; -} -export interface Config1 { - receivers: [string, Uint128][]; -} -export interface InstantiateMsg { - config: Config1; -} - - -function isSigningCosmWasmClient( - client: CosmWasmClient | SigningCosmWasmClient -): client is SigningCosmWasmClient { - return 'execute' in client; -} - -export class Client { - private readonly client: CosmWasmClient | SigningCosmWasmClient; - contractAddress: string; - constructor(client: CosmWasmClient | SigningCosmWasmClient, contractAddress: string) { - this.client = client; - this.contractAddress = contractAddress; - } - mustBeSigningClient() { - return new Error("This client is not a SigningCosmWasmClient"); - } - static async instantiate( - client: SigningCosmWasmClient, - sender: string, - codeId: number, - initMsg: InstantiateMsg, - label: string, - fees: StdFee | 'auto' | number, - initCoins?: readonly Coin[], - ): Promise { - const res = await client.instantiate(sender, codeId, initMsg, label, fees, { - ...(initCoins && initCoins.length && { funds: initCoins }), - }); - return res; - } - static async instantiate2( - client: SigningCosmWasmClient, - sender: string, - codeId: number, - salt: number, - initMsg: InstantiateMsg, - label: string, - fees: StdFee | 'auto' | number, - initCoins?: readonly Coin[], - ): Promise { - const res = await client.instantiate2(sender, codeId, new Uint8Array([salt]), initMsg, label, fees, { - ...(initCoins && initCoins.length && { funds: initCoins }), - }); - return res; - } - queryConfig = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { config: {} }); - } - queryOwnership = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { ownership: {} }); - } - distribute = async(sender:string, args: DistributeArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { distribute: args }, fee || "auto", memo, funds); - } - updateConfig = async(sender:string, args: UpdateConfigArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { update_config: args }, fee || "auto", memo, funds); - } - updateOwnership = async(sender:string, args: UpdateOwnershipArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { update_ownership: args }, fee || "auto", memo, funds); - } -} From 94ec2a7de002d78ed774d1895d39cb9d88b92c68 Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Thu, 7 Nov 2024 15:40:04 +0100 Subject: [PATCH 02/14] feat: contract locator --- contracts/factory/Cargo.toml | 2 +- contracts/factory/src/contract.rs | 28 +++++++++++++++++++++- contracts/factory/src/tests.rs | 26 ++++++++++++++++++++ integration_tests/yarn.lock | 17 +++++++++---- packages/base/src/msg/factory.rs | 2 ++ ts-client/lib/contractLib/dropFactory.d.ts | 8 ++++++- ts-client/lib/contractLib/dropFactory.js | 3 +++ ts-client/src/contractLib/dropFactory.ts | 10 +++++++- 8 files changed, 88 insertions(+), 8 deletions(-) diff --git a/contracts/factory/Cargo.toml b/contracts/factory/Cargo.toml index 5187badf..0cdd64b1 100644 --- a/contracts/factory/Cargo.toml +++ b/contracts/factory/Cargo.toml @@ -37,4 +37,4 @@ cw-ownable = { workspace = true } semver = { workspace = true } [dev-dependencies] -cw-multi-test = { workspace = true } \ No newline at end of file +cw-multi-test = { workspace = true } diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 78019227..0b473e2a 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -1,7 +1,7 @@ use crate::error::ContractResult; use cosmwasm_std::{ attr, instantiate2_address, to_json_binary, Binary, CodeInfoResponse, CosmosMsg, Deps, DepsMut, - Env, HexBinary, MessageInfo, Response, StdResult, Uint128, WasmMsg, + Env, HexBinary, MessageInfo, Response, StdError, StdResult, Uint128, WasmMsg, }; use drop_helpers::answer::response; use drop_staking_base::state::splitter::Config as SplitterConfig; @@ -456,9 +456,35 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult query_locate(deps, contracts), } } +fn query_locate(deps: Deps, items: Vec) -> StdResult { + let state = STATE.load(deps.storage)?; + let mut contracts: Vec<(String, String)> = vec![]; + for item in items { + let addr = match item.as_str() { + "token" => state.token_contract.to_string(), + "core" => state.core_contract.to_string(), + "puppeteer" => state.puppeteer_contract.to_string(), + "withdrawal_voucher" => state.withdrawal_voucher_contract.to_string(), + "withdrawal_manager" => state.withdrawal_manager_contract.to_string(), + "strategy" => state.strategy_contract.to_string(), + "validators_set" => state.validators_set_contract.to_string(), + "distribution" => state.distribution_contract.to_string(), + "rewards_manager" => state.rewards_manager_contract.to_string(), + "rewards_pump" => state.rewards_pump_contract.to_string(), + "splitter" => state.splitter_contract.to_string(), + "lsm_share_bond_provider" => state.lsm_share_bond_provider_contract.to_string(), + "native_bond_provider" => state.native_bond_provider_contract.to_string(), + _ => return Err(StdError::generic_err("Unknown item")), + }; + contracts.push((item, addr)); + } + to_json_binary(&contracts) +} + fn query_pause_info(deps: Deps) -> StdResult { let state = STATE.load(deps.storage)?; diff --git a/contracts/factory/src/tests.rs b/contracts/factory/src/tests.rs index d8f02027..497a9a6d 100644 --- a/contracts/factory/src/tests.rs +++ b/contracts/factory/src/tests.rs @@ -1096,6 +1096,32 @@ fn test_query_state() { assert_eq!(query_res, get_default_factory_state()); } +#[test] +fn test_query_locate() { + let mut deps = mock_dependencies(&[]); + STATE + .save(deps.as_mut().storage, &get_default_factory_state()) + .unwrap(); + let query_res: Vec<(String, String)> = from_json( + query( + deps.as_ref(), + mock_env(), + QueryMsg::Locate { + contracts: vec!["core".to_string(), "token".to_string()], + }, + ) + .unwrap(), + ) + .unwrap(); + assert_eq!( + query_res, + vec![ + ("core".to_string(), "core_contract".to_string()), + ("token".to_string(), "token_contract".to_string()) + ] + ); +} + #[test] fn test_query_pause_info() { let mut deps = mock_dependencies(&[]); diff --git a/integration_tests/yarn.lock b/integration_tests/yarn.lock index f958892c..ff718dba 100644 --- a/integration_tests/yarn.lock +++ b/integration_tests/yarn.lock @@ -962,9 +962,9 @@ integrity sha512-Z3TNyBL8Vd/M9D9Ms2S3LmFq2sSMzahodD6rCS9V2N44HUMINb75jNkSuwAx7eo2ufqTdfOdtGQpNbieUjPQmw== "@types/lodash@^4.17.0": - version "4.17.12" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.12.tgz#25d71312bf66512105d71e55d42e22c36bcfc689" - integrity sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ== + version "4.17.13" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.13.tgz#786e2d67cfd95e32862143abe7463a7f90c300eb" + integrity sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg== "@types/long@^4.0.1": version "4.0.2" @@ -1655,7 +1655,16 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^7.0.0, cross-spawn@^7.0.2: +cross-spawn@^7.0.0: + version "7.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.5.tgz#910aac880ff5243da96b728bc6521a5f6c2f2f82" + integrity sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== diff --git a/packages/base/src/msg/factory.rs b/packages/base/src/msg/factory.rs index 9661d19d..1331548d 100644 --- a/packages/base/src/msg/factory.rs +++ b/packages/base/src/msg/factory.rs @@ -86,6 +86,8 @@ pub struct MigrateMsg {} pub enum QueryMsg { #[returns(crate::state::factory::State)] State {}, + #[returns(Vec<(String, String)>)] + Locate { contracts: Vec }, #[returns(crate::state::factory::PauseInfoResponse)] PauseInfo {}, } diff --git a/ts-client/lib/contractLib/dropFactory.d.ts b/ts-client/lib/contractLib/dropFactory.d.ts index d031b0af..f8023653 100644 --- a/ts-client/lib/contractLib/dropFactory.d.ts +++ b/ts-client/lib/contractLib/dropFactory.d.ts @@ -1,5 +1,6 @@ import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult, InstantiateResult } from "@cosmjs/cosmwasm-stargate"; import { StdFee } from "@cosmjs/amino"; +export type ArrayOfTupleOfStringAndString = [string, string][]; /** * Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future) */ @@ -669,7 +670,8 @@ export type UpdateOwnershipArgs = { }; } | "accept_ownership" | "renounce_ownership"; export interface DropFactorySchema { - responses: OwnershipForString | PauseInfoResponse | State; + responses: ArrayOfTupleOfStringAndString | OwnershipForString | PauseInfoResponse | State; + query: LocateArgs; execute: UpdateConfigArgs | ProxyArgs | AdminExecuteArgs | UpdateOwnershipArgs; instantiate?: InstantiateMsg; [k: string]: unknown; @@ -716,6 +718,9 @@ export interface State { withdrawal_manager_contract: string; withdrawal_voucher_contract: string; } +export interface LocateArgs { + contracts: string[]; +} export interface ConfigOptional { base_denom?: string | null; bond_limit?: Uint128 | null; @@ -1213,6 +1218,7 @@ export declare class Client { static instantiate(client: SigningCosmWasmClient, sender: string, codeId: number, initMsg: InstantiateMsg, label: string, fees: StdFee | 'auto' | number, initCoins?: readonly Coin[]): Promise; static instantiate2(client: SigningCosmWasmClient, sender: string, codeId: number, salt: number, initMsg: InstantiateMsg, label: string, fees: StdFee | 'auto' | number, initCoins?: readonly Coin[]): Promise; queryState: () => Promise; + queryLocate: (args: LocateArgs) => Promise; queryPauseInfo: () => Promise; queryOwnership: () => Promise; updateConfig: (sender: string, args: UpdateConfigArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => Promise; diff --git a/ts-client/lib/contractLib/dropFactory.js b/ts-client/lib/contractLib/dropFactory.js index c8444be2..428b8a42 100644 --- a/ts-client/lib/contractLib/dropFactory.js +++ b/ts-client/lib/contractLib/dropFactory.js @@ -29,6 +29,9 @@ class Client { queryState = async () => { return this.client.queryContractSmart(this.contractAddress, { state: {} }); }; + queryLocate = async (args) => { + return this.client.queryContractSmart(this.contractAddress, { locate: args }); + }; queryPauseInfo = async () => { return this.client.queryContractSmart(this.contractAddress, { pause_info: {} }); }; diff --git a/ts-client/src/contractLib/dropFactory.ts b/ts-client/src/contractLib/dropFactory.ts index f72b6c28..c4ec4e3e 100644 --- a/ts-client/src/contractLib/dropFactory.ts +++ b/ts-client/src/contractLib/dropFactory.ts @@ -1,5 +1,6 @@ import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult, InstantiateResult } from "@cosmjs/cosmwasm-stargate"; import { StdFee } from "@cosmjs/amino"; +export type ArrayOfTupleOfStringAndString = [string, string][]; /** * Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future) */ @@ -739,7 +740,8 @@ export type UpdateOwnershipArgs = | "renounce_ownership"; export interface DropFactorySchema { - responses: OwnershipForString | PauseInfoResponse | State; + responses: ArrayOfTupleOfStringAndString | OwnershipForString | PauseInfoResponse | State; + query: LocateArgs; execute: UpdateConfigArgs | ProxyArgs | AdminExecuteArgs | UpdateOwnershipArgs; instantiate?: InstantiateMsg; [k: string]: unknown; @@ -786,6 +788,9 @@ export interface State { withdrawal_manager_contract: string; withdrawal_voucher_contract: string; } +export interface LocateArgs { + contracts: string[]; +} export interface ConfigOptional { base_denom?: string | null; bond_limit?: Uint128 | null; @@ -1325,6 +1330,9 @@ export class Client { queryState = async(): Promise => { return this.client.queryContractSmart(this.contractAddress, { state: {} }); } + queryLocate = async(args: LocateArgs): Promise => { + return this.client.queryContractSmart(this.contractAddress, { locate: args }); + } queryPauseInfo = async(): Promise => { return this.client.queryContractSmart(this.contractAddress, { pause_info: {} }); } From 5758e7aed62446cffa02880dbb84e7fd0748406a Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Thu, 7 Nov 2024 19:14:32 +0100 Subject: [PATCH 03/14] feat: make state as HashMap --- contracts/factory/src/contract.rs | 215 +++++++++++--------- contracts/factory/src/tests.rs | 217 ++++++++++++++++----- packages/base/src/msg/factory.rs | 6 +- packages/base/src/state/factory.rs | 22 +-- ts-client/lib/contractLib/dropFactory.d.ts | 26 +-- ts-client/src/contractLib/dropFactory.ts | 26 +-- 6 files changed, 309 insertions(+), 203 deletions(-) diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 0b473e2a..999ed21b 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -1,7 +1,9 @@ +use std::collections::HashMap; + use crate::error::ContractResult; use cosmwasm_std::{ attr, instantiate2_address, to_json_binary, Binary, CodeInfoResponse, CosmosMsg, Deps, DepsMut, - Env, HexBinary, MessageInfo, Response, StdError, StdResult, Uint128, WasmMsg, + Env, HexBinary, MessageInfo, Response, StdResult, Uint128, WasmMsg, }; use drop_helpers::answer::response; use drop_staking_base::state::splitter::Config as SplitterConfig; @@ -10,7 +12,7 @@ use drop_staking_base::{ ExecuteMsg, InstantiateMsg, MigrateMsg, ProxyMsg, QueryMsg, UpdateConfigMsg, ValidatorSetMsg, }, - state::factory::{State, STATE}, + state::factory::STATE, }; use drop_staking_base::{ msg::{ @@ -185,54 +187,78 @@ pub fn instantiate( native_bond_provider_address.to_string(), )); - let core_contract = deps.api.addr_humanize(&core_address)?.to_string(); - let token_contract = deps.api.addr_humanize(&token_address)?.to_string(); - let withdrawal_voucher_contract = deps - .api - .addr_humanize(&withdrawal_voucher_address)? - .to_string(); - let withdrawal_manager_contract = deps - .api - .addr_humanize(&withdrawal_manager_address)? - .to_string(); - let strategy_contract = deps.api.addr_humanize(&strategy_address)?.to_string(); - let validators_set_contract = deps.api.addr_humanize(&validators_set_address)?.to_string(); - let distribution_contract = deps - .api - .addr_humanize(&distribution_calculator_address)? - .to_string(); - let puppeteer_contract = deps.api.addr_humanize(&puppeteer_address)?.to_string(); - let rewards_manager_contract = deps - .api - .addr_humanize(&rewards_manager_address)? - .to_string(); - let rewards_pump_contract = deps.api.addr_humanize(&rewards_pump_address)?.to_string(); - let splitter_contract = deps.api.addr_humanize(&splitter_address)?.to_string(); - let lsm_share_bond_provider_contract = deps - .api - .addr_humanize(&lsm_share_bond_provider_address)? - .to_string(); - let native_bond_provider_contract = deps - .api - .addr_humanize(&native_bond_provider_address)? - .to_string(); - - let state = State { - token_contract: token_contract.to_string(), - core_contract: core_contract.to_string(), - puppeteer_contract: puppeteer_contract.to_string(), - withdrawal_voucher_contract: withdrawal_voucher_contract.to_string(), - withdrawal_manager_contract: withdrawal_manager_contract.to_string(), - strategy_contract: strategy_contract.to_string(), - validators_set_contract: validators_set_contract.to_string(), - distribution_contract: distribution_contract.to_string(), - rewards_manager_contract: rewards_manager_contract.to_string(), - rewards_pump_contract: rewards_pump_contract.to_string(), - splitter_contract: splitter_contract.to_string(), - lsm_share_bond_provider_contract: lsm_share_bond_provider_contract.to_string(), - native_bond_provider_contract: native_bond_provider_contract.to_string(), - }; - STATE.save(deps.storage, &state)?; + let core_contract = deps.api.addr_humanize(&core_address)?; + let token_contract = deps.api.addr_humanize(&token_address)?; + let withdrawal_voucher_contract = deps.api.addr_humanize(&withdrawal_voucher_address)?; + let withdrawal_manager_contract = deps.api.addr_humanize(&withdrawal_manager_address)?; + let strategy_contract = deps.api.addr_humanize(&strategy_address)?; + let validators_set_contract = deps.api.addr_humanize(&validators_set_address)?; + let distribution_contract = deps.api.addr_humanize(&distribution_calculator_address)?; + let puppeteer_contract = deps.api.addr_humanize(&puppeteer_address)?; + let rewards_manager_contract = deps.api.addr_humanize(&rewards_manager_address)?; + let rewards_pump_contract = deps.api.addr_humanize(&rewards_pump_address)?; + let splitter_contract = deps.api.addr_humanize(&splitter_address)?; + let lsm_share_bond_provider_contract = + deps.api.addr_humanize(&lsm_share_bond_provider_address)?; + let native_bond_provider_contract = deps.api.addr_humanize(&native_bond_provider_address)?; + + STATE.save(deps.storage, "token_contract".to_string(), &token_contract)?; + STATE.save(deps.storage, "core_contract".to_string(), &core_contract)?; + STATE.save( + deps.storage, + "puppeteer_contract".to_string(), + &puppeteer_contract, + )?; + STATE.save( + deps.storage, + "withdrawal_voucher_contract".to_string(), + &withdrawal_voucher_contract, + )?; + STATE.save( + deps.storage, + "withdrawal_manager_contract".to_string(), + &withdrawal_manager_contract, + )?; + STATE.save( + deps.storage, + "strategy_contract".to_string(), + &strategy_contract, + )?; + STATE.save( + deps.storage, + "validators_set_contract".to_string(), + &validators_set_contract, + )?; + STATE.save( + deps.storage, + "distribution_contract".to_string(), + &distribution_contract, + )?; + STATE.save( + deps.storage, + "rewards_manager_contract".to_string(), + &rewards_manager_contract, + )?; + STATE.save( + deps.storage, + "rewards_pump_contract".to_string(), + &rewards_pump_contract, + )?; + STATE.save( + deps.storage, + "splitter_contract".to_string(), + &splitter_contract, + )?; + STATE.save( + deps.storage, + "lsm_share_bond_provider_contract".to_string(), + &lsm_share_bond_provider_contract, + )?; + STATE.save( + deps.storage, + "native_bond_provider_contract".to_string(), + &native_bond_provider_contract, + )?; let msgs = vec![ CosmosMsg::Wasm(WasmMsg::Instantiate2 { @@ -412,7 +438,7 @@ pub fn instantiate( owner: env.contract.address.to_string(), core_contract: core_contract.to_string(), puppeteer_contract: puppeteer_contract.to_string(), - validators_set_contract, + validators_set_contract: validators_set_contract.to_string(), port_id: msg.remote_opts.port_id.to_string(), transfer_channel_id: msg.remote_opts.transfer_channel_id.to_string(), timeout: msg.remote_opts.timeout.local, @@ -450,7 +476,7 @@ pub fn instantiate( #[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { match msg { - QueryMsg::State {} => to_json_binary(&STATE.load(deps.storage)?), + QueryMsg::State {} => query_state(deps), QueryMsg::PauseInfo {} => query_pause_info(deps), QueryMsg::Ownership {} => { let ownership = cw_ownable::get_ownership(deps.storage)?; @@ -460,46 +486,39 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult) -> StdResult { + let state = STATE + .range(deps.storage, None, None, cosmwasm_std::Order::Ascending) + .collect::>>()?; + to_json_binary(&state) +} + fn query_locate(deps: Deps, items: Vec) -> StdResult { - let state = STATE.load(deps.storage)?; - let mut contracts: Vec<(String, String)> = vec![]; + let mut contracts: HashMap = HashMap::new(); for item in items { - let addr = match item.as_str() { - "token" => state.token_contract.to_string(), - "core" => state.core_contract.to_string(), - "puppeteer" => state.puppeteer_contract.to_string(), - "withdrawal_voucher" => state.withdrawal_voucher_contract.to_string(), - "withdrawal_manager" => state.withdrawal_manager_contract.to_string(), - "strategy" => state.strategy_contract.to_string(), - "validators_set" => state.validators_set_contract.to_string(), - "distribution" => state.distribution_contract.to_string(), - "rewards_manager" => state.rewards_manager_contract.to_string(), - "rewards_pump" => state.rewards_pump_contract.to_string(), - "splitter" => state.splitter_contract.to_string(), - "lsm_share_bond_provider" => state.lsm_share_bond_provider_contract.to_string(), - "native_bond_provider" => state.native_bond_provider_contract.to_string(), - _ => return Err(StdError::generic_err("Unknown item")), - }; - contracts.push((item, addr)); + contracts.insert(item.clone(), STATE.load(deps.storage, item)?.to_string()); } to_json_binary(&contracts) } fn query_pause_info(deps: Deps) -> StdResult { - let state = STATE.load(deps.storage)?; + let core_contract = STATE.load(deps.storage, "core_contract".to_string())?; + let withdrawal_manager_contract = + STATE.load(deps.storage, "withdrawal_manager_contract".to_string())?; + let rewards_manager_contract = + STATE.load(deps.storage, "rewards_manager_contract".to_string())?; to_json_binary(&drop_staking_base::state::factory::PauseInfoResponse { core: deps .querier - .query_wasm_smart(state.core_contract, &CoreQueryMsg::Pause {})?, + .query_wasm_smart(core_contract, &CoreQueryMsg::Pause {})?, withdrawal_manager: deps.querier.query_wasm_smart( - state.withdrawal_manager_contract, + withdrawal_manager_contract, &WithdrawalManagerQueryMsg::PauseInfo {}, )?, - rewards_manager: deps.querier.query_wasm_smart( - state.rewards_manager_contract, - &RewardsQueryMsg::PauseInfo {}, - )?, + rewards_manager: deps + .querier + .query_wasm_smart(rewards_manager_contract, &RewardsQueryMsg::PauseInfo {})?, }) .map_err(From::from) } @@ -530,11 +549,15 @@ pub fn execute( fn exec_pause(deps: DepsMut, info: MessageInfo) -> ContractResult> { cw_ownable::assert_owner(deps.storage, &info.sender)?; - let state = STATE.load(deps.storage)?; + let core_contract = STATE.load(deps.storage, "core_contract".to_string())?; + let rewards_manager_contract = + STATE.load(deps.storage, "rewards_manager_contract".to_string())?; + let withdrawal_manager_contract = + STATE.load(deps.storage, "withdrawal_manager_contract".to_string())?; let attrs = vec![attr("action", "pause")]; let messages = vec![ get_proxied_message( - state.core_contract, + core_contract.to_string(), drop_staking_base::msg::core::ExecuteMsg::SetPause( drop_staking_base::state::core::Pause { tick: true, @@ -545,12 +568,12 @@ fn exec_pause(deps: DepsMut, info: MessageInfo) -> ContractResult ContractResult ContractResult> { cw_ownable::assert_owner(deps.storage, &info.sender)?; - let state = STATE.load(deps.storage)?; + let core_contract = STATE.load(deps.storage, "core_contract".to_string())?; + let rewards_manager_contract = + STATE.load(deps.storage, "rewards_manager_contract".to_string())?; + let withdrawal_manager_contract = + STATE.load(deps.storage, "withdrawal_manager_contract".to_string())?; let attrs = vec![attr("action", "unpause")]; let messages = vec![ get_proxied_message( - state.core_contract, + core_contract.to_string(), drop_staking_base::msg::core::ExecuteMsg::SetPause( drop_staking_base::state::core::Pause { tick: false, @@ -575,12 +602,12 @@ fn exec_unpause(deps: DepsMut, info: MessageInfo) -> ContractResult ContractResult> { let attrs = vec![attr("action", "update-config")]; cw_ownable::assert_owner(deps.storage, &info.sender)?; - let state = STATE.load(deps.storage)?; + let core_contract = STATE.load(deps.storage, "core_contract".to_string())?; + let validators_set_contract = + STATE.load(deps.storage, "validators_set_contract".to_string())?; let mut messages = vec![]; match msg { UpdateConfigMsg::Core(msg) => messages.push(get_proxied_message( - state.core_contract, + core_contract.to_string(), drop_staking_base::msg::core::ExecuteMsg::UpdateConfig { new_config: Box::new(*msg), }, info.funds, )?), UpdateConfigMsg::ValidatorsSet(new_config) => messages.push(get_proxied_message( - state.validators_set_contract, + validators_set_contract.to_string(), drop_staking_base::msg::validatorset::ExecuteMsg::UpdateConfig { new_config }, info.funds, )?), @@ -632,7 +661,9 @@ fn execute_proxy_msg( info: MessageInfo, msg: ProxyMsg, ) -> ContractResult> { - let state = STATE.load(deps.storage)?; + let validators_set_contract = + STATE.load(deps.storage, "validators_set_contract".to_string())?; + let puppeteer_contract = STATE.load(deps.storage, "puppeteer_contract".to_string())?; let mut messages = vec![]; let attrs = vec![attr("action", "proxy-call")]; cw_ownable::assert_owner(deps.storage, &info.sender)?; @@ -640,14 +671,14 @@ fn execute_proxy_msg( ProxyMsg::ValidatorSet(msg) => match msg { ValidatorSetMsg::UpdateValidators { validators } => { messages.push(get_proxied_message( - state.validators_set_contract, + validators_set_contract.to_string(), drop_staking_base::msg::validatorset::ExecuteMsg::UpdateValidators { validators: validators.clone(), }, vec![], )?); messages.push(get_proxied_message( - state.puppeteer_contract, + puppeteer_contract.to_string(), drop_staking_base::msg::puppeteer::ExecuteMsg::RegisterBalanceAndDelegatorDelegationsQuery { validators: validators.iter().map(|v| {v.valoper_address.to_string()}).collect() }, info.funds, )?) diff --git a/contracts/factory/src/tests.rs b/contracts/factory/src/tests.rs index 497a9a6d..5ba4c9a6 100644 --- a/contracts/factory/src/tests.rs +++ b/contracts/factory/src/tests.rs @@ -2,7 +2,7 @@ use crate::contract::{execute, instantiate, query}; use cosmwasm_std::{ attr, from_json, testing::{mock_env, mock_info}, - to_json_binary, BankMsg, Uint128, + to_json_binary, Addr, BankMsg, DepsMut, Uint128, }; use drop_helpers::testing::{mock_dependencies, mock_dependencies_with_api}; use drop_staking_base::{ @@ -10,7 +10,7 @@ use drop_staking_base::{ CoreParams, ExecuteMsg, FeeParams, InstantiateMsg, LsmShareBondParams, NativeBondParams, QueryMsg, UpdateConfigMsg, ValidatorSetMsg, }, - state::factory::{CodeIds, RemoteOpts, State, Timeout, STATE}, + state::factory::{CodeIds, RemoteOpts, Timeout, STATE}, }; use drop_staking_base::{ msg::{ @@ -37,23 +37,101 @@ use drop_staking_base::{ }, state::{core::Pause as CorePause, pump::PumpTimeout, splitter::Config as SplitterConfig}, }; +use neutron_sdk::bindings::query::NeutronQuery; +use std::collections::HashMap; -fn get_default_factory_state() -> State { - State { - token_contract: "token_contract".to_string(), - core_contract: "core_contract".to_string(), - puppeteer_contract: "puppeteer_contract".to_string(), - withdrawal_voucher_contract: "withdrawal_voucher_contract".to_string(), - withdrawal_manager_contract: "withdrawal_manager_contract".to_string(), - strategy_contract: "strategy_contract".to_string(), - validators_set_contract: "validators_set_contract".to_string(), - distribution_contract: "distribution_contract".to_string(), - rewards_manager_contract: "rewards_manager_contract".to_string(), - rewards_pump_contract: "rewards_pump_contract".to_string(), - splitter_contract: "splitter_contract".to_string(), - lsm_share_bond_provider_contract: "lsm_share_bond_provider_contract".to_string(), - native_bond_provider_contract: "native_bond_provider_contract".to_string(), - } +fn set_default_factory_state(deps: DepsMut) { + STATE + .save( + deps.storage, + "token_contract".to_string(), + &Addr::unchecked("token_contract".to_string()), + ) + .unwrap(); + STATE + .save( + deps.storage, + "core_contract".to_string(), + &Addr::unchecked("core_contract".to_string()), + ) + .unwrap(); + STATE + .save( + deps.storage, + "puppeteer_contract".to_string(), + &Addr::unchecked("puppeteer_contract".to_string()), + ) + .unwrap(); + STATE + .save( + deps.storage, + "withdrawal_voucher_contract".to_string(), + &Addr::unchecked("withdrawal_voucher_contract".to_string()), + ) + .unwrap(); + STATE + .save( + deps.storage, + "withdrawal_manager_contract".to_string(), + &Addr::unchecked("withdrawal_manager_contract".to_string()), + ) + .unwrap(); + STATE + .save( + deps.storage, + "strategy_contract".to_string(), + &Addr::unchecked("strategy_contract".to_string()), + ) + .unwrap(); + STATE + .save( + deps.storage, + "validators_set_contract".to_string(), + &Addr::unchecked("validators_set_contract".to_string()), + ) + .unwrap(); + STATE + .save( + deps.storage, + "distribution_contract".to_string(), + &Addr::unchecked("distribution_contract".to_string()), + ) + .unwrap(); + STATE + .save( + deps.storage, + "rewards_manager_contract".to_string(), + &Addr::unchecked("rewards_manager_contract".to_string()), + ) + .unwrap(); + STATE + .save( + deps.storage, + "rewards_pump_contract".to_string(), + &Addr::unchecked("rewards_pump_contract".to_string()), + ) + .unwrap(); + STATE + .save( + deps.storage, + "splitter_contract".to_string(), + &Addr::unchecked("splitter_contract".to_string()), + ) + .unwrap(); + STATE + .save( + deps.storage, + "lsm_share_bond_provider_contract".to_string(), + &Addr::unchecked("lsm_share_bond_provider_contract".to_string()), + ) + .unwrap(); + STATE + .save( + deps.storage, + "native_bond_provider_contract".to_string(), + &Addr::unchecked("native_bond_provider_contract".to_string()), + ) + .unwrap(); } #[test] @@ -570,10 +648,7 @@ fn test_update_config_core() { let mut deps = mock_dependencies(&[]); let deps_mut = deps.as_mut(); let _ = cw_ownable::initialize_owner(deps_mut.storage, deps_mut.api, Some("owner")).unwrap(); - STATE - .save(deps_mut.storage, &get_default_factory_state()) - .unwrap(); - + set_default_factory_state(deps.as_mut()); let new_core_config = drop_staking_base::state::core::ConfigOptional { token_contract: Some("token_contract1".to_string()), puppeteer_contract: Some("puppeteer_contract1".to_string()), @@ -655,9 +730,7 @@ fn test_update_config_validators_set() { let mut deps = mock_dependencies(&[]); let deps_mut = deps.as_mut(); let _ = cw_ownable::initialize_owner(deps_mut.storage, deps_mut.api, Some("owner")).unwrap(); - STATE - .save(deps_mut.storage, &get_default_factory_state()) - .unwrap(); + set_default_factory_state(deps.as_mut()); let new_validator_set_config = drop_staking_base::state::validatorset::ConfigOptional { stats_contract: Some("validator_stats_contract".to_string()), @@ -700,9 +773,7 @@ fn test_proxy_validators_set_update_validators_unauthorized() { let mut deps = mock_dependencies(&[]); let deps_mut = deps.as_mut(); let _ = cw_ownable::initialize_owner(deps_mut.storage, deps_mut.api, Some("owner")).unwrap(); - STATE - .save(deps_mut.storage, &get_default_factory_state()) - .unwrap(); + set_default_factory_state(deps.as_mut()); let res = execute( deps.as_mut().into_empty(), mock_env(), @@ -736,9 +807,7 @@ fn test_proxy_validators_set_update_validators() { let mut deps = mock_dependencies(&[]); let deps_mut = deps.as_mut(); let _ = cw_ownable::initialize_owner(deps_mut.storage, deps_mut.api, Some("owner")).unwrap(); - STATE - .save(deps_mut.storage, &get_default_factory_state()) - .unwrap(); + set_default_factory_state(deps.as_mut()); let res = execute( deps.as_mut().into_empty(), @@ -956,9 +1025,7 @@ fn test_pause() { let mut deps = mock_dependencies(&[]); let deps_mut = deps.as_mut(); let _ = cw_ownable::initialize_owner(deps_mut.storage, deps_mut.api, Some("owner")).unwrap(); - STATE - .save(deps.as_mut().storage, &get_default_factory_state()) - .unwrap(); + set_default_factory_state(deps.as_mut()); let res = execute( deps.as_mut().into_empty(), mock_env(), @@ -1032,9 +1099,7 @@ fn test_unpause() { let mut deps = mock_dependencies(&[]); let deps_mut = deps.as_mut(); let _ = cw_ownable::initialize_owner(deps_mut.storage, deps_mut.api, Some("owner")).unwrap(); - STATE - .save(deps.as_mut().storage, &get_default_factory_state()) - .unwrap(); + set_default_factory_state(deps.as_mut()); let res = execute( deps.as_mut().into_empty(), mock_env(), @@ -1088,26 +1153,72 @@ fn test_unpause() { #[test] fn test_query_state() { let mut deps = mock_dependencies(&[]); - STATE - .save(deps.as_mut().storage, &get_default_factory_state()) - .unwrap(); - let query_res: drop_staking_base::state::factory::State = + set_default_factory_state(deps.as_mut()); + let query_res: HashMap = from_json(query(deps.as_ref(), mock_env(), QueryMsg::State {}).unwrap()).unwrap(); - assert_eq!(query_res, get_default_factory_state()); + assert_eq!( + query_res, + HashMap::from([ + ("core_contract".to_string(), "core_contract".to_string()), + ("token_contract".to_string(), "token_contract".to_string()), + ( + "puppeteer_contract".to_string(), + "puppeteer_contract".to_string() + ), + ( + "withdrawal_voucher_contract".to_string(), + "withdrawal_voucher_contract".to_string() + ), + ( + "withdrawal_manager_contract".to_string(), + "withdrawal_manager_contract".to_string() + ), + ( + "strategy_contract".to_string(), + "strategy_contract".to_string() + ), + ( + "validators_set_contract".to_string(), + "validators_set_contract".to_string() + ), + ( + "distribution_contract".to_string(), + "distribution_contract".to_string() + ), + ( + "rewards_manager_contract".to_string(), + "rewards_manager_contract".to_string() + ), + ( + "rewards_pump_contract".to_string(), + "rewards_pump_contract".to_string() + ), + ( + "splitter_contract".to_string(), + "splitter_contract".to_string() + ), + ( + "lsm_share_bond_provider_contract".to_string(), + "lsm_share_bond_provider_contract".to_string() + ), + ( + "native_bond_provider_contract".to_string(), + "native_bond_provider_contract".to_string() + ) + ]) + ); } #[test] fn test_query_locate() { let mut deps = mock_dependencies(&[]); - STATE - .save(deps.as_mut().storage, &get_default_factory_state()) - .unwrap(); - let query_res: Vec<(String, String)> = from_json( + set_default_factory_state(deps.as_mut()); + let query_res: HashMap = from_json( query( deps.as_ref(), mock_env(), QueryMsg::Locate { - contracts: vec!["core".to_string(), "token".to_string()], + contracts: vec!["core_contract".to_string(), "token_contract".to_string()], }, ) .unwrap(), @@ -1115,10 +1226,10 @@ fn test_query_locate() { .unwrap(); assert_eq!( query_res, - vec![ - ("core".to_string(), "core_contract".to_string()), - ("token".to_string(), "token_contract".to_string()) - ] + HashMap::from([ + ("core_contract".to_string(), "core_contract".to_string()), + ("token_contract".to_string(), "token_contract".to_string()), + ]) ); } @@ -1144,9 +1255,7 @@ fn test_query_pause_info() { .add_wasm_query_response("rewards_manager_contract", |_| -> cosmwasm_std::Binary { to_json_binary(&drop_helpers::pause::PauseInfoResponse::Paused {}).unwrap() }); - STATE - .save(deps.as_mut().storage, &get_default_factory_state()) - .unwrap(); + set_default_factory_state(deps.as_mut()); let query_res: drop_staking_base::state::factory::PauseInfoResponse = from_json(query(deps.as_ref(), mock_env(), QueryMsg::PauseInfo {}).unwrap()).unwrap(); assert_eq!( diff --git a/packages/base/src/msg/factory.rs b/packages/base/src/msg/factory.rs index 1331548d..d4137cf5 100644 --- a/packages/base/src/msg/factory.rs +++ b/packages/base/src/msg/factory.rs @@ -5,6 +5,8 @@ use cosmwasm_std::{CosmosMsg, Decimal, Uint128}; use cw_ownable::cw_ownable_execute; use drop_macros::pausable; use neutron_sdk::bindings::msg::NeutronMsg; +#[allow(unused_imports)] +use std::collections::HashMap; #[cw_serde] pub struct InstantiateMsg { @@ -84,9 +86,9 @@ pub struct MigrateMsg {} #[cw_serde] #[derive(QueryResponses)] pub enum QueryMsg { - #[returns(crate::state::factory::State)] + #[returns(HashMap)] State {}, - #[returns(Vec<(String, String)>)] + #[returns(HashMap)] Locate { contracts: Vec }, #[returns(crate::state::factory::PauseInfoResponse)] PauseInfo {}, diff --git a/packages/base/src/state/factory.rs b/packages/base/src/state/factory.rs index 9e759cd8..eaf05791 100644 --- a/packages/base/src/state/factory.rs +++ b/packages/base/src/state/factory.rs @@ -1,5 +1,6 @@ use cosmwasm_schema::cw_serde; -use cw_storage_plus::Item; +use cosmwasm_std::Addr; +use cw_storage_plus::Map; #[cw_serde] pub struct CodeIds { @@ -35,23 +36,6 @@ pub struct Timeout { pub remote: u64, } -#[cw_serde] -pub struct State { - pub token_contract: String, - pub core_contract: String, - pub puppeteer_contract: String, - pub withdrawal_voucher_contract: String, - pub withdrawal_manager_contract: String, - pub strategy_contract: String, - pub validators_set_contract: String, - pub distribution_contract: String, - pub rewards_manager_contract: String, - pub rewards_pump_contract: String, - pub splitter_contract: String, - pub lsm_share_bond_provider_contract: String, - pub native_bond_provider_contract: String, -} - #[cw_serde] pub struct PauseInfoResponse { pub withdrawal_manager: drop_helpers::pause::PauseInfoResponse, @@ -59,4 +43,4 @@ pub struct PauseInfoResponse { pub rewards_manager: drop_helpers::pause::PauseInfoResponse, } -pub const STATE: Item = Item::new("state"); +pub const STATE: Map = Map::new("state"); diff --git a/ts-client/lib/contractLib/dropFactory.d.ts b/ts-client/lib/contractLib/dropFactory.d.ts index f8023653..c19f60c5 100644 --- a/ts-client/lib/contractLib/dropFactory.d.ts +++ b/ts-client/lib/contractLib/dropFactory.d.ts @@ -1,6 +1,5 @@ import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult, InstantiateResult } from "@cosmjs/cosmwasm-stargate"; import { StdFee } from "@cosmjs/amino"; -export type ArrayOfTupleOfStringAndString = [string, string][]; /** * Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future) */ @@ -670,12 +669,15 @@ export type UpdateOwnershipArgs = { }; } | "accept_ownership" | "renounce_ownership"; export interface DropFactorySchema { - responses: ArrayOfTupleOfStringAndString | OwnershipForString | PauseInfoResponse | State; + responses: MapOfString | OwnershipForString | PauseInfoResponse | MapOfString1; query: LocateArgs; execute: UpdateConfigArgs | ProxyArgs | AdminExecuteArgs | UpdateOwnershipArgs; instantiate?: InstantiateMsg; [k: string]: unknown; } +export interface MapOfString { + [k: string]: string; +} /** * The contract's ownership info */ @@ -703,20 +705,8 @@ export interface Pause { tick: boolean; unbond: boolean; } -export interface State { - core_contract: string; - distribution_contract: string; - lsm_share_bond_provider_contract: string; - native_bond_provider_contract: string; - puppeteer_contract: string; - rewards_manager_contract: string; - rewards_pump_contract: string; - splitter_contract: string; - strategy_contract: string; - token_contract: string; - validators_set_contract: string; - withdrawal_manager_contract: string; - withdrawal_voucher_contract: string; +export interface MapOfString1 { + [k: string]: string; } export interface LocateArgs { contracts: string[]; @@ -1217,8 +1207,8 @@ export declare class Client { mustBeSigningClient(): Error; static instantiate(client: SigningCosmWasmClient, sender: string, codeId: number, initMsg: InstantiateMsg, label: string, fees: StdFee | 'auto' | number, initCoins?: readonly Coin[]): Promise; static instantiate2(client: SigningCosmWasmClient, sender: string, codeId: number, salt: number, initMsg: InstantiateMsg, label: string, fees: StdFee | 'auto' | number, initCoins?: readonly Coin[]): Promise; - queryState: () => Promise; - queryLocate: (args: LocateArgs) => Promise; + queryState: () => Promise; + queryLocate: (args: LocateArgs) => Promise; queryPauseInfo: () => Promise; queryOwnership: () => Promise; updateConfig: (sender: string, args: UpdateConfigArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => Promise; diff --git a/ts-client/src/contractLib/dropFactory.ts b/ts-client/src/contractLib/dropFactory.ts index c4ec4e3e..09ae816c 100644 --- a/ts-client/src/contractLib/dropFactory.ts +++ b/ts-client/src/contractLib/dropFactory.ts @@ -1,6 +1,5 @@ import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult, InstantiateResult } from "@cosmjs/cosmwasm-stargate"; import { StdFee } from "@cosmjs/amino"; -export type ArrayOfTupleOfStringAndString = [string, string][]; /** * Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future) */ @@ -740,12 +739,15 @@ export type UpdateOwnershipArgs = | "renounce_ownership"; export interface DropFactorySchema { - responses: ArrayOfTupleOfStringAndString | OwnershipForString | PauseInfoResponse | State; + responses: MapOfString | OwnershipForString | PauseInfoResponse | MapOfString1; query: LocateArgs; execute: UpdateConfigArgs | ProxyArgs | AdminExecuteArgs | UpdateOwnershipArgs; instantiate?: InstantiateMsg; [k: string]: unknown; } +export interface MapOfString { + [k: string]: string; +} /** * The contract's ownership info */ @@ -773,20 +775,8 @@ export interface Pause { tick: boolean; unbond: boolean; } -export interface State { - core_contract: string; - distribution_contract: string; - lsm_share_bond_provider_contract: string; - native_bond_provider_contract: string; - puppeteer_contract: string; - rewards_manager_contract: string; - rewards_pump_contract: string; - splitter_contract: string; - strategy_contract: string; - token_contract: string; - validators_set_contract: string; - withdrawal_manager_contract: string; - withdrawal_voucher_contract: string; +export interface MapOfString1 { + [k: string]: string; } export interface LocateArgs { contracts: string[]; @@ -1327,10 +1317,10 @@ export class Client { }); return res; } - queryState = async(): Promise => { + queryState = async(): Promise => { return this.client.queryContractSmart(this.contractAddress, { state: {} }); } - queryLocate = async(args: LocateArgs): Promise => { + queryLocate = async(args: LocateArgs): Promise => { return this.client.queryContractSmart(this.contractAddress, { locate: args }); } queryPauseInfo = async(): Promise => { From 94d7d05c4eb3277c6de5639d13f41ab4985b18ce Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Fri, 8 Nov 2024 14:46:17 +0100 Subject: [PATCH 04/14] feat: macro phonebook --- contracts/core/src/contract.rs | 109 +++---- contracts/core/src/tests.rs | 489 ++++++++++++++++++++++++++++-- contracts/factory/src/contract.rs | 7 +- contracts/factory/src/tests.rs | 24 +- packages/base/src/msg/core.rs | 18 +- packages/base/src/state/core.rs | 15 +- packages/helpers/src/lib.rs | 1 + packages/helpers/src/phonebook.rs | 29 ++ 8 files changed, 553 insertions(+), 139 deletions(-) create mode 100644 packages/helpers/src/phonebook.rs diff --git a/contracts/core/src/contract.rs b/contracts/core/src/contract.rs index d7ff962f..d35a08a6 100644 --- a/contracts/core/src/contract.rs +++ b/contracts/core/src/contract.rs @@ -1,8 +1,10 @@ +use std::collections::HashMap; + use cosmwasm_schema::cw_serde; use cosmwasm_std::{ attr, ensure, ensure_eq, ensure_ne, to_json_binary, Addr, Attribute, BankQuery, Binary, Coin, CosmosMsg, CustomQuery, Decimal, Deps, DepsMut, Env, MessageInfo, Order, QueryRequest, Reply, - Response, StdError, StdResult, SubMsg, SubMsgResult, Uint128, Uint64, WasmMsg, + Response, StdError, StdResult, SubMsg, SubMsgResult, Uint128, Uint64, WasmMsg, WasmQuery, }; use cw_storage_plus::Bound; use drop_helpers::answer::response; @@ -50,21 +52,20 @@ pub fn instantiate( ) -> ContractResult> { cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; let attrs: Vec = vec![ - attr("token_contract", &msg.token_contract), - attr("puppeteer_contract", &msg.puppeteer_contract), - attr("strategy_contract", &msg.strategy_contract), + attr("factory_contract", &msg.factory_contract), attr("base_denom", &msg.base_denom), attr("owner", &msg.owner), ]; cw_ownable::initialize_owner(deps.storage, deps.api, Some(&msg.owner))?; let config = msg.into_config(deps.as_ref().into_empty())?; + let addrs = drop_helpers::get_contracts!(deps, config.factory_contract, token_contract); CONFIG.save(deps.storage, &config)?; LD_DENOM.save( deps.storage, &deps .querier .query_wasm_smart::( - &config.token_contract, + &addrs.token_contract, &TokenQueryMsg::Config {}, )? .denom, @@ -141,6 +142,7 @@ fn query_bond_providers(deps: Deps) -> ContractResult> { fn query_exchange_rate(deps: Deps, config: &Config) -> ContractResult { let fsm_state = FSM.get_current_state(deps.storage)?; + let addrs = drop_helpers::get_contracts!(deps, config.factory_contract, puppeteer_contract); if fsm_state != ContractState::Idle { return Ok(EXCHANGE_RATE .load(deps.storage) @@ -160,7 +162,7 @@ fn query_exchange_rate(deps: Deps, config: &Config) -> ContractRes let delegations_response = deps .querier .query_wasm_smart::( - &config.puppeteer_contract, + &addrs.puppeteer_contract, &drop_puppeteer_base::msg::QueryMsg::Extension { msg: drop_staking_base::msg::puppeteer::QueryExtMsg::Delegations {}, }, @@ -442,7 +444,9 @@ fn execute_update_withdrawn_amount( withdrawn_amount: Uint128, ) -> ContractResult> { let config = CONFIG.load(deps.storage)?; - if info.sender != config.withdrawal_manager_contract { + let addrs = + drop_helpers::get_contracts!(deps, config.factory_contract, withdrawal_manager_contract); + if info.sender != addrs.withdrawal_manager_contract { return Err(ContractError::Unauthorized {}); } @@ -469,8 +473,8 @@ fn execute_puppeteer_hook( msg: drop_puppeteer_base::peripheral_hook::ResponseHookMsg, ) -> ContractResult> { let config = CONFIG.load(deps.storage)?; - - let allowed_senders: Vec<_> = vec![config.puppeteer_contract] + let addrs = drop_helpers::get_contracts!(deps, config.factory_contract, puppeteer_contract); + let allowed_senders: Vec<_> = vec![deps.api.addr_validate(&addrs.puppeteer_contract)?] .into_iter() .chain(BOND_PROVIDERS.get_all_providers(deps.as_ref().storage)?) .collect(); @@ -522,8 +526,14 @@ fn execute_tick( let current_state = FSM.get_current_state(deps.storage)?; let config = CONFIG.load(deps.storage)?; + let addrs = drop_helpers::get_contracts!( + deps, + config.factory_contract, + puppeteer_contract, + validators_set_contract + ); - check_latest_icq_responses(deps.as_ref(), config.puppeteer_contract.to_string())?; + check_latest_icq_responses(deps.as_ref(), addrs.puppeteer_contract)?; match current_state { ContractState::Idle => execute_tick_idle(deps.branch(), env, info, &config), @@ -546,6 +556,12 @@ fn execute_tick_idle( let mut messages = vec![]; let mut sub_msgs = vec![]; cache_exchange_rate(deps.branch(), env.clone(), config)?; + let addrs = drop_helpers::get_contracts!( + deps, + config.factory_contract, + puppeteer_contract, + validators_set_contract + ); attrs.push(attr("knot", "002")); attrs.push(attr("knot", "003")); if env.block.time.seconds() - last_idle_call < config.idle_min_interval { @@ -599,7 +615,7 @@ fn execute_tick_idle( .ok_or(ContractError::PumpIcaAddressIsNotSet {})?; let (ica_balance, _remote_height, ica_balance_local_time) = get_ica_balance_by_denom( deps.as_ref(), - config.puppeteer_contract.as_ref(), + &addrs.puppeteer_contract, &config.remote_denom, true, )?; @@ -698,14 +714,14 @@ fn execute_tick_idle( }; let validators: Vec = deps.querier.query_wasm_smart( - config.validators_set_contract.to_string(), + addrs.validators_set_contract.to_string(), &drop_staking_base::msg::validatorset::QueryMsg::Validators {}, )?; let delegations_response = deps .querier .query_wasm_smart::( - config.puppeteer_contract.to_string(), + addrs.puppeteer_contract.to_string(), &drop_puppeteer_base::msg::QueryMsg::Extension { msg: drop_staking_base::msg::puppeteer::QueryExtMsg::Delegations {}, }, @@ -736,7 +752,7 @@ fn execute_tick_idle( if !validators_to_claim.is_empty() { attrs.push(attr("validators_to_claim", validators_to_claim.join(","))); messages.push(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.puppeteer_contract.to_string(), + contract_addr: addrs.puppeteer_contract.to_string(), msg: to_json_binary( &drop_staking_base::msg::puppeteer::ExecuteMsg::ClaimRewardsAndOptionalyTransfer { validators: validators_to_claim, @@ -766,7 +782,7 @@ fn execute_tick_peripheral( ) -> ContractResult> { let mut attrs = vec![attr("action", "tick_peripheral")]; let res = get_received_puppeteer_response(deps.as_ref())?; - + let addrs = drop_helpers::get_contracts!(deps, config.factory_contract, puppeteer_contract); if let drop_puppeteer_base::peripheral_hook::ResponseHookMsg::Success(msg) = res { match msg.transaction { drop_puppeteer_base::peripheral_hook::Transaction::RedeemShares { .. } => { @@ -783,7 +799,7 @@ fn execute_tick_peripheral( let balances_response: drop_staking_base::msg::puppeteer::BalancesResponse = deps.querier.query_wasm_smart( - config.puppeteer_contract.to_string(), + addrs.puppeteer_contract.to_string(), &drop_puppeteer_base::msg::QueryMsg::Extension { msg: drop_staking_base::msg::puppeteer::QueryExtMsg::Balances {}, }, @@ -951,6 +967,7 @@ fn execute_bond( let config = CONFIG.load(deps.storage)?; let bonded_coin = cw_utils::one_coin(&info)?; + let addrs = drop_helpers::get_contracts!(deps, config.factory_contract, token_contract); let Coin { amount, denom } = bonded_coin.clone(); if let Some(bond_limit) = config.bond_limit { if BONDED_AMOUNT.load(deps.storage)? + amount > bond_limit { @@ -1012,7 +1029,7 @@ fn execute_bond( } } msgs.push(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.token_contract.to_string(), + contract_addr: addrs.token_contract.to_string(), msg: to_json_binary(&TokenExecuteMsg::Mint { amount: issue_amount, receiver, @@ -1064,33 +1081,9 @@ fn execute_update_config( let mut config = CONFIG.load(deps.storage)?; cw_ownable::assert_owner(deps.storage, &info.sender)?; let mut attrs = vec![attr("action", "update_config")]; - if let Some(token_contract) = new_config.token_contract { - config.token_contract = deps.api.addr_validate(&token_contract)?; - attrs.push(attr("token_contract", token_contract)); - } - if let Some(puppeteer_contract) = new_config.puppeteer_contract { - config.puppeteer_contract = deps.api.addr_validate(&puppeteer_contract)?; - attrs.push(attr("puppeteer_contract", puppeteer_contract)); - } - if let Some(strategy_contract) = new_config.strategy_contract { - config.strategy_contract = deps.api.addr_validate(&strategy_contract)?; - attrs.push(attr("strategy_contract", strategy_contract)); - } - if let Some(withdrawal_voucher_contract) = new_config.withdrawal_voucher_contract { - config.withdrawal_voucher_contract = - deps.api.addr_validate(&withdrawal_voucher_contract)?; - attrs.push(attr( - "withdrawal_voucher_contract", - withdrawal_voucher_contract, - )); - } - if let Some(withdrawal_manager_contract) = new_config.withdrawal_manager_contract { - config.withdrawal_manager_contract = - deps.api.addr_validate(&withdrawal_manager_contract)?; - attrs.push(attr( - "withdrawal_manager_contract", - withdrawal_manager_contract, - )); + if let Some(factory_contract) = new_config.factory_contract { + config.factory_contract = deps.api.addr_validate(&factory_contract)?; + attrs.push(attr("factory_contract", factory_contract)); } if let Some(pump_ica_address) = new_config.pump_ica_address { attrs.push(attr("pump_address", &pump_ica_address)); @@ -1104,10 +1097,6 @@ fn execute_update_config( attrs.push(attr("remote_denom", &remote_denom)); config.remote_denom = remote_denom; } - if let Some(validators_set_contract) = new_config.validators_set_contract { - config.validators_set_contract = deps.api.addr_validate(&validators_set_contract)?; - attrs.push(attr("validators_set_contract", validators_set_contract)); - } if let Some(base_denom) = new_config.base_denom { attrs.push(attr("base_denom", &base_denom)); config.base_denom = base_denom; @@ -1168,6 +1157,12 @@ fn execute_unbond( let config = CONFIG.load(deps.storage)?; let ld_denom = LD_DENOM.load(deps.storage)?; let dasset_amount = cw_utils::must_pay(&info, &ld_denom)?; + let addrs = drop_helpers::get_contracts!( + deps, + config.factory_contract, + withdrawal_voucher_contract, + token_contract + ); BONDED_AMOUNT.update(deps.storage, |total| StdResult::Ok(total - dasset_amount))?; let mut unbond_batch = unbond_batches_map().load(deps.storage, unbond_batch_id)?; unbond_batch.total_unbond_items += 1; @@ -1195,7 +1190,7 @@ fn execute_unbond( let msgs = vec![ CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.withdrawal_voucher_contract.into_string(), + contract_addr: addrs.withdrawal_voucher_contract, msg: to_json_binary(&VoucherExecuteMsg::Mint { owner: info.sender.to_string(), token_id: unbond_batch_id.to_string() @@ -1209,7 +1204,7 @@ fn execute_unbond( funds: vec![], }), CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.token_contract.into_string(), + contract_addr: addrs.token_contract, msg: to_json_binary(&TokenExecuteMsg::Burn {})?, funds: vec![Coin { denom: ld_denom, @@ -1268,6 +1263,12 @@ fn get_unbonding_msg( info: &MessageInfo, attrs: &mut Vec, ) -> ContractResult>> { + let addrs = drop_helpers::get_contracts!( + deps, + config.factory_contract, + strategy_contract, + puppeteer_contract + ); let funds = info.funds.clone(); attrs.push(attr("knot", "024")); let (batch_id, processing_failed_batch) = match FAILED_BATCH_ID.may_load(deps.storage)? { @@ -1292,7 +1293,7 @@ fn get_unbonding_msg( let calc_withdraw_query_result: Result, StdError> = deps.querier.query_wasm_smart( - config.strategy_contract.to_string(), + addrs.strategy_contract, &drop_staking_base::msg::strategy::QueryMsg::CalcWithdraw { withdraw: expected_native_asset_amount, }, @@ -1321,7 +1322,7 @@ fn get_unbonding_msg( )?; } Ok(Some(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.puppeteer_contract.to_string(), + contract_addr: addrs.puppeteer_contract, msg: to_json_binary(&drop_staking_base::msg::puppeteer::ExecuteMsg::Undelegate { items: undelegations, batch_id, @@ -1489,6 +1490,8 @@ pub mod check_denom { if denom == config.base_denom { return Ok(DenomType::Base); } + let addrs = + drop_helpers::get_contracts!(deps, config.factory_contract, validators_set_contract); let trace = query_denom_trace(deps, denom)?.denom_trace; let (port, channel) = trace @@ -1510,7 +1513,7 @@ pub mod check_denom { let validator_info = deps .querier .query_wasm_smart::( - &config.validators_set_contract, + &addrs.validators_set_contract, &drop_staking_base::msg::validatorset::QueryMsg::Validator { valoper: validator.to_string(), }, diff --git a/contracts/core/src/tests.rs b/contracts/core/src/tests.rs index 39f02a06..849b8ecf 100644 --- a/contracts/core/src/tests.rs +++ b/contracts/core/src/tests.rs @@ -35,10 +35,7 @@ use neutron_sdk::{ bindings::query::NeutronQuery, interchain_queries::v045::types::Balances, sudo::msg::RequestPacket, }; -use std::vec; - -pub const MOCK_PUPPETEER_CONTRACT_ADDR: &str = "puppeteer_contract"; -pub const MOCK_STRATEGY_CONTRACT_ADDR: &str = "strategy_contract"; +use std::{collections::HashMap, vec}; fn get_default_config( idle_min_interval: u64, @@ -46,12 +43,7 @@ fn get_default_config( unbond_batch_switch_time: u64, ) -> Config { Config { - token_contract: Addr::unchecked("token_contract"), - puppeteer_contract: Addr::unchecked(MOCK_PUPPETEER_CONTRACT_ADDR), - strategy_contract: Addr::unchecked(MOCK_STRATEGY_CONTRACT_ADDR), - withdrawal_voucher_contract: Addr::unchecked("withdrawal_voucher_contract"), - withdrawal_manager_contract: Addr::unchecked("withdrawal_manager_contract"), - validators_set_contract: Addr::unchecked("validators_set_contract"), + factory_contract: Addr::unchecked("factory_contract"), base_denom: "base_denom".to_string(), remote_denom: "remote_denom".to_string(), idle_min_interval, @@ -82,6 +74,13 @@ fn get_default_unbond_batch_status_timestamps() -> UnbondBatchStatusTimestamps { #[test] fn test_update_config() { let mut deps = mock_dependencies(&[]); + deps.querier.add_wasm_query_response("token_contract", |_| { + to_json_binary(&drop_staking_base::msg::token::ConfigResponse { + core_address: "core_contract".to_string(), + denom: "ld_denom".to_string(), + }) + .unwrap() + }); deps.querier .add_wasm_query_response("old_token_contract", |_| { to_json_binary(&drop_staking_base::msg::token::ConfigResponse { @@ -90,6 +89,10 @@ fn test_update_config() { }) .unwrap() }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([("token_contract", "token_contract")])).unwrap() + }); let env = mock_env(); let info = mock_info("admin", &[]); let mut deps_mut = deps.as_mut(); @@ -98,12 +101,7 @@ fn test_update_config() { env.clone(), info.clone(), InstantiateMsg { - token_contract: "old_token_contract".to_string(), - puppeteer_contract: "old_puppeteer_contract".to_string(), - strategy_contract: "old_strategy_contract".to_string(), - withdrawal_voucher_contract: "old_withdrawal_voucher_contract".to_string(), - withdrawal_manager_contract: "old_withdrawal_manager_contract".to_string(), - validators_set_contract: "old_validators_set_contract".to_string(), + factory_contract: "factory_contract".to_string(), base_denom: "old_base_denom".to_string(), remote_denom: "old_remote_denom".to_string(), idle_min_interval: 12, @@ -125,13 +123,7 @@ fn test_update_config() { ); let new_config = ConfigOptional { - token_contract: Some("new_token_contract".to_string()), - puppeteer_contract: Some("new_puppeteer_contract".to_string()), - strategy_contract: Some("new_strategy_contract".to_string()), - staker_contract: Some("new_staker_contract".to_string()), - withdrawal_voucher_contract: Some("new_withdrawal_voucher_contract".to_string()), - withdrawal_manager_contract: Some("new_withdrawal_manager_contract".to_string()), - validators_set_contract: Some("new_validators_set_contract".to_string()), + factory_contract: Some("new_factory_contract".to_string()), base_denom: Some("new_base_denom".to_string()), remote_denom: Some("new_remote_denom".to_string()), idle_min_interval: Some(2), @@ -145,12 +137,7 @@ fn test_update_config() { emergency_address: Some("new_emergency_address".to_string()), }; let expected_config = Config { - token_contract: Addr::unchecked("new_token_contract"), - puppeteer_contract: Addr::unchecked("new_puppeteer_contract"), - strategy_contract: Addr::unchecked("new_strategy_contract"), - withdrawal_voucher_contract: Addr::unchecked("new_withdrawal_voucher_contract"), - withdrawal_manager_contract: Addr::unchecked("new_withdrawal_manager_contract"), - validators_set_contract: Addr::unchecked("new_validators_set_contract"), + factory_contract: Addr::unchecked("new_factory_contract"), base_denom: "new_base_denom".to_string(), remote_denom: "new_remote_denom".to_string(), idle_min_interval: 2, @@ -208,7 +195,22 @@ fn test_update_withdrawn_amount() { CONFIG .save(deps.as_mut().storage, &get_default_config(1000, 10, 6000)) .unwrap(); - + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([( + "withdrawal_manager_contract", + "withdrawal_manager_contract", + )])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([( + "withdrawal_manager_contract", + "withdrawal_manager_contract", + )])) + .unwrap() + }); let withdrawn_batch = &UnbondBatch { total_dasset_amount_to_withdraw: Uint128::from(1001u128), expected_native_asset_amount: Uint128::from(1001u128), @@ -274,6 +276,22 @@ fn test_update_withdrawn_amount() { #[test] fn test_execute_reset_bonded_amount() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); let deps_mut = deps.as_mut(); cw_ownable::initialize_owner(deps_mut.storage, deps_mut.api, Some("admin")).unwrap(); BONDED_AMOUNT @@ -299,6 +317,22 @@ fn test_execute_reset_bonded_amount() { #[test] fn test_add_remove_bond_provider() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); let deps_mut = deps.as_mut(); cw_ownable::initialize_owner(deps_mut.storage, deps_mut.api, Some("admin")).unwrap(); @@ -362,6 +396,30 @@ fn test_add_remove_bond_provider() { #[test] fn test_execute_tick_idle_process_bondig_provider() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); BOND_PROVIDERS.init(deps.as_mut().storage).unwrap(); deps.querier @@ -457,6 +515,30 @@ fn test_execute_tick_idle_process_bondig_provider() { #[test] fn test_tick_idle_claim_wo_unbond() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); deps.querier .add_wasm_query_response("puppeteer_contract", |_| { to_json_binary(&BalancesResponse { @@ -617,6 +699,30 @@ fn test_tick_idle_claim_wo_unbond() { #[test] fn test_tick_idle_claim_with_unbond_transfer() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); deps.querier .add_wasm_query_response("puppeteer_contract", |_| { to_json_binary(&BalancesResponse { @@ -773,6 +879,22 @@ fn test_tick_idle_claim_with_unbond_transfer() { #[test] fn test_tick_no_puppeteer_response() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); CONFIG .save(deps.as_mut().storage, &get_default_config(1000, 100, 600)) .unwrap(); @@ -822,6 +944,22 @@ fn test_tick_no_puppeteer_response() { fn test_tick_claiming_error_wo_transfer() { // no unbonded batch, no pending transfer for stake, some balance in ICA to stake let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); deps.querier .add_wasm_query_response("puppeteer_contract", |_| { to_json_binary(&BalancesResponse { @@ -932,6 +1070,22 @@ fn test_tick_claiming_error_wo_transfer() { fn test_tick_claiming_error_with_transfer() { // no unbonded batch, no pending transfer for stake, some balance in ICA to stake let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); deps.querier .add_wasm_query_response("puppeteer_contract", |_| { to_json_binary(&BalancesResponse { @@ -1074,6 +1228,30 @@ fn test_tick_claiming_error_with_transfer() { fn test_tick_claiming_wo_transfer_unbonding() { // no unbonded batch, no pending transfer for stake, no balance on ICA, but we have unbond batch to switch let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([( + "puppeteer_contract", + "puppeteer_contract", + )])) + .unwrap() + }); deps.querier .add_wasm_query_response("puppeteer_contract", |_| { to_json_binary(&BalancesResponse { @@ -1258,6 +1436,22 @@ fn test_tick_claiming_wo_idle() { // no unbonded batch, no pending transfer for stake, no balance on ICA, // and no unbond batch to switch, so we go to idle let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); LAST_ICA_CHANGE_HEIGHT .save(deps.as_mut().storage, &0) .unwrap(); @@ -1408,6 +1602,14 @@ fn test_tick_claiming_wo_idle() { #[test] fn test_execute_tick_guard_balance_outdated() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); CONFIG .save(deps.as_mut().storage, &get_default_config(1000, 100, 600)) .unwrap(); @@ -1448,6 +1650,14 @@ fn test_execute_tick_guard_balance_outdated() { #[test] fn test_execute_tick_guard_delegations_outdated() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); CONFIG .save(deps.as_mut().storage, &get_default_config(1000, 100, 600)) .unwrap(); @@ -1500,6 +1710,14 @@ fn test_execute_tick_guard_delegations_outdated() { #[test] fn test_execute_tick_staking_no_puppeteer_response() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); CONFIG .save(deps.as_mut().storage, &get_default_config(1000, 100, 600)) .unwrap(); @@ -1546,6 +1764,14 @@ fn test_execute_tick_staking_no_puppeteer_response() { #[test] fn test_execute_tick_unbonding_no_puppeteer_response() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); CONFIG .save(deps.as_mut().storage, &get_default_config(1000, 100, 600)) .unwrap(); @@ -1593,6 +1819,18 @@ fn test_execute_tick_unbonding_no_puppeteer_response() { #[test] fn test_bond_wo_receiver() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([("token_contract", "token_contract")])).unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([( + "puppeteer_contract", + "puppeteer_contract", + )])) + .unwrap() + }); BOND_PROVIDERS.init(deps.as_mut().storage).unwrap(); deps.querier @@ -1677,6 +1915,18 @@ fn test_bond_wo_receiver() { #[test] fn test_bond_with_receiver() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([("token_contract", "token_contract")])).unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([( + "puppeteer_contract", + "puppeteer_contract", + )])) + .unwrap() + }); BOND_PROVIDERS.init(deps.as_mut().storage).unwrap(); deps.querier @@ -1800,6 +2050,18 @@ fn test_bond_lsm_share_increase_exchange_rate() { denom: "ld_denom".to_string(), amount: Uint128::new(1001), }]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([("token_contract", "token_contract")])).unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([( + "puppeteer_contract", + "puppeteer_contract", + )])) + .unwrap() + }); BOND_PROVIDERS.init(deps.as_mut().storage).unwrap(); deps.querier @@ -1916,6 +2178,14 @@ fn test_bond_lsm_share_increase_exchange_rate() { fn test_unbond() { let mut deps = mock_dependencies(&[]); let mut env = mock_env(); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("token_contract", "token_contract"), + ("withdrawal_voucher_contract", "withdrawal_voucher_contract"), + ])) + .unwrap() + }); env.block.time = Timestamp::from_seconds(1000); FSM.set_initial_state(deps.as_mut().storage, ContractState::Idle) .unwrap(); @@ -2236,6 +2506,30 @@ mod check_denom { #[test] fn invalid_port() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([( + "validators_set_contract", + "validators_set_contract", + )])) + .unwrap() + }); deps.querier.add_stargate_query_response( "/ibc.applications.transfer.v1.Query/DenomTrace", |_| { @@ -2260,6 +2554,22 @@ mod check_denom { #[test] fn invalid_channel() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); deps.querier.add_stargate_query_response( "/ibc.applications.transfer.v1.Query/DenomTrace", |_| { @@ -2284,6 +2594,22 @@ mod check_denom { #[test] fn invalid_port_and_channel() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); deps.querier.add_stargate_query_response( "/ibc.applications.transfer.v1.Query/DenomTrace", |_| { @@ -2308,6 +2634,22 @@ mod check_denom { #[test] fn not_an_lsm_share() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); deps.querier.add_stargate_query_response( "/ibc.applications.transfer.v1.Query/DenomTrace", |_| { @@ -2332,6 +2674,22 @@ mod check_denom { #[test] fn unknown_validator() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); deps.querier.add_stargate_query_response( "/ibc.applications.transfer.v1.Query/DenomTrace", |_| { @@ -2376,6 +2734,22 @@ mod check_denom { #[test] fn invalid_validator_index() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); deps.querier.add_stargate_query_response( "/ibc.applications.transfer.v1.Query/DenomTrace", |_| { @@ -2400,6 +2774,22 @@ mod check_denom { #[test] fn known_validator() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("validators_set_contract", "validators_set_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([ + ("strategy_contract", "strategy_contract"), + ("puppeteer_contract", "puppeteer_contract"), + ])) + .unwrap() + }); deps.querier.add_stargate_query_response( "/ibc.applications.transfer.v1.Query/DenomTrace", |_| { @@ -2456,6 +2846,8 @@ mod check_denom { } mod bond_hooks { + use std::collections::HashMap; + use super::*; use cosmwasm_std::ReplyOn; use drop_staking_base::msg::core::{BondCallback, BondHook}; @@ -2608,6 +3000,18 @@ mod bond_hooks { #[test] fn execute_bond_with_active_bond_hook_no_ref() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([("token_contract", "token_contract")])).unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([( + "puppeteer_contract", + "puppeteer_contract", + )])) + .unwrap() + }); BOND_PROVIDERS.init(deps.as_mut().storage).unwrap(); deps.querier @@ -2682,6 +3086,18 @@ mod bond_hooks { #[test] fn execute_bond_with_active_bond_hook() { let mut deps = mock_dependencies(&[]); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([("token_contract", "token_contract")])).unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([( + "puppeteer_contract", + "puppeteer_contract", + )])) + .unwrap() + }); BOND_PROVIDERS.init(deps.as_mut().storage).unwrap(); deps.querier @@ -2763,7 +3179,18 @@ mod bond_hooks { .add_wasm_query_response("native_provider_address", |_| { to_json_binary(&true).unwrap() }); - + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([("token_contract", "token_contract")])).unwrap() + }); + deps.querier + .add_wasm_query_response("factory_contract", |_| { + to_json_binary(&HashMap::from([( + "puppeteer_contract", + "puppeteer_contract", + )])) + .unwrap() + }); deps.querier .add_wasm_query_response("native_provider_address", |_| { to_json_binary(&Uint128::from(1000u128)).unwrap() diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 999ed21b..15c2918e 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -337,15 +337,10 @@ pub fn instantiate( code_id: msg.code_ids.core_code_id, label: get_contract_label("core"), msg: to_json_binary(&CoreInstantiateMsg { - token_contract: token_contract.to_string(), - puppeteer_contract: puppeteer_contract.to_string(), - strategy_contract: strategy_contract.to_string(), - withdrawal_voucher_contract: withdrawal_voucher_contract.to_string(), - withdrawal_manager_contract: withdrawal_manager_contract.to_string(), + factory_contract: env.contract.address.to_string(), base_denom: msg.base_denom.clone(), remote_denom: msg.remote_opts.denom.to_string(), pump_ica_address: None, - validators_set_contract: validators_set_contract.to_string(), unbonding_period: msg.core_params.unbonding_period, unbonding_safe_period: msg.core_params.unbonding_safe_period, unbond_batch_switch_time: msg.core_params.unbond_batch_switch_time, diff --git a/contracts/factory/src/tests.rs b/contracts/factory/src/tests.rs index 5ba4c9a6..ffa8a68b 100644 --- a/contracts/factory/src/tests.rs +++ b/contracts/factory/src/tests.rs @@ -335,12 +335,8 @@ fn test_instantiate() { code_id: 2, label: "drop-staking-core".to_string(), msg: to_json_binary(&CoreInstantiateMsg { - token_contract: "some_humanized_address".to_string(), - puppeteer_contract: "some_humanized_address".to_string(), - strategy_contract: "some_humanized_address".to_string(), - withdrawal_voucher_contract: "some_humanized_address".to_string(), - withdrawal_manager_contract: "some_humanized_address".to_string(), - validators_set_contract: "some_humanized_address".to_string(), + factory_contract: "factory_contract".to_string(), + base_denom: "base_denom".to_string(), remote_denom: "denom".to_string(), idle_min_interval: 0, @@ -609,13 +605,7 @@ fn test_update_config_core_unauthorized() { let deps_mut = deps.as_mut(); let _ = cw_ownable::initialize_owner(deps_mut.storage, deps_mut.api, Some("owner")).unwrap(); let new_core_config = drop_staking_base::state::core::ConfigOptional { - token_contract: None, - puppeteer_contract: None, - strategy_contract: None, - staker_contract: None, - withdrawal_voucher_contract: None, - withdrawal_manager_contract: None, - validators_set_contract: None, + factory_contract: None, base_denom: None, remote_denom: None, idle_min_interval: None, @@ -650,13 +640,7 @@ fn test_update_config_core() { let _ = cw_ownable::initialize_owner(deps_mut.storage, deps_mut.api, Some("owner")).unwrap(); set_default_factory_state(deps.as_mut()); let new_core_config = drop_staking_base::state::core::ConfigOptional { - token_contract: Some("token_contract1".to_string()), - puppeteer_contract: Some("puppeteer_contract1".to_string()), - strategy_contract: Some("strategy_contract1".to_string()), - staker_contract: Some("staker_contract1".to_string()), - withdrawal_voucher_contract: Some("withdrawal_voucher_contract1".to_string()), - withdrawal_manager_contract: Some("withdrawal_manager_contract1".to_string()), - validators_set_contract: Some("validators_set_contract1".to_string()), + factory_contract: Some("factory_contract1".to_string()), base_denom: Some("base_denom1".to_string()), remote_denom: Some("remote_denom1".to_string()), idle_min_interval: Some(1u64), diff --git a/packages/base/src/msg/core.rs b/packages/base/src/msg/core.rs index ff6a9440..8f794e41 100644 --- a/packages/base/src/msg/core.rs +++ b/packages/base/src/msg/core.rs @@ -11,12 +11,7 @@ use drop_puppeteer_base::peripheral_hook::ResponseHookMsg as PuppeteerResponseHo #[cw_serde] pub struct InstantiateMsg { - pub token_contract: String, - pub puppeteer_contract: String, - pub strategy_contract: String, - pub withdrawal_voucher_contract: String, - pub withdrawal_manager_contract: String, - pub validators_set_contract: String, + pub factory_contract: String, pub base_denom: String, pub remote_denom: String, pub idle_min_interval: u64, //seconds @@ -34,15 +29,7 @@ pub struct InstantiateMsg { impl InstantiateMsg { pub fn into_config(self, deps: Deps) -> ContractResult { Ok(Config { - token_contract: deps.api.addr_validate(&self.token_contract)?, - puppeteer_contract: deps.api.addr_validate(&self.puppeteer_contract)?, - strategy_contract: deps.api.addr_validate(&self.strategy_contract)?, - withdrawal_voucher_contract: deps - .api - .addr_validate(&self.withdrawal_voucher_contract)?, - withdrawal_manager_contract: deps - .api - .addr_validate(&self.withdrawal_manager_contract)?, + factory_contract: deps.api.addr_validate(&self.factory_contract)?, base_denom: self.base_denom, remote_denom: self.remote_denom, idle_min_interval: self.idle_min_interval, @@ -50,7 +37,6 @@ impl InstantiateMsg { unbonding_period: self.unbonding_period, pump_ica_address: self.pump_ica_address, transfer_channel_id: self.transfer_channel_id, - validators_set_contract: deps.api.addr_validate(&self.validators_set_contract)?, bond_limit: match self.bond_limit { None => None, Some(limit) if limit.is_zero() => None, diff --git a/packages/base/src/state/core.rs b/packages/base/src/state/core.rs index 0a1b7b48..7a8d25e4 100644 --- a/packages/base/src/state/core.rs +++ b/packages/base/src/state/core.rs @@ -8,13 +8,7 @@ use super::bond_providers::BondProviders; #[cw_serde] pub struct ConfigOptional { - pub token_contract: Option, - pub puppeteer_contract: Option, - pub strategy_contract: Option, - pub staker_contract: Option, - pub withdrawal_voucher_contract: Option, - pub withdrawal_manager_contract: Option, - pub validators_set_contract: Option, + pub factory_contract: Option, pub base_denom: Option, pub remote_denom: Option, pub idle_min_interval: Option, @@ -30,12 +24,7 @@ pub struct ConfigOptional { #[cw_serde] pub struct Config { - pub token_contract: Addr, - pub puppeteer_contract: Addr, - pub strategy_contract: Addr, - pub withdrawal_voucher_contract: Addr, - pub withdrawal_manager_contract: Addr, - pub validators_set_contract: Addr, + pub factory_contract: Addr, pub base_denom: String, pub remote_denom: String, pub idle_min_interval: u64, //seconds diff --git a/packages/helpers/src/lib.rs b/packages/helpers/src/lib.rs index 09b94856..4420af5e 100644 --- a/packages/helpers/src/lib.rs +++ b/packages/helpers/src/lib.rs @@ -7,6 +7,7 @@ pub mod icq; pub mod icq_initia; pub mod interchain; pub mod pause; +pub mod phonebook; pub mod query_id; pub mod testing; pub mod validation; diff --git a/packages/helpers/src/phonebook.rs b/packages/helpers/src/phonebook.rs new file mode 100644 index 00000000..478e6219 --- /dev/null +++ b/packages/helpers/src/phonebook.rs @@ -0,0 +1,29 @@ +#[macro_export] +macro_rules! get_contracts { + ($deps:expr, $factory_contract:expr, $($field_name:ident),*) => { + { + #[derive(Debug)] + struct Phonebook { + $( + $field_name: String, + )* + } + let contracts = $deps + .querier + .query::>(&QueryRequest::Wasm(WasmQuery::Smart { + contract_addr: $factory_contract.to_string(), + msg: to_json_binary(&drop_staking_base::msg::factory::QueryMsg::Locate { + contracts: vec![$(stringify!($field_name).to_string()),*], + })?, + }))?; + + Phonebook { + $( + $field_name: contracts.get(stringify!($field_name)) + .unwrap_or_else(|| panic!("Field {} not found in contracts", stringify!($field_name))) + .to_string(), + )* + } + } + }; +} From dfe7c400bc0477141fb02c292468a6933f316b1d Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Mon, 11 Nov 2024 12:01:02 +0700 Subject: [PATCH 05/14] fix: review --- contracts/core/src/contract.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/contracts/core/src/contract.rs b/contracts/core/src/contract.rs index d35a08a6..16a52dde 100644 --- a/contracts/core/src/contract.rs +++ b/contracts/core/src/contract.rs @@ -526,12 +526,7 @@ fn execute_tick( let current_state = FSM.get_current_state(deps.storage)?; let config = CONFIG.load(deps.storage)?; - let addrs = drop_helpers::get_contracts!( - deps, - config.factory_contract, - puppeteer_contract, - validators_set_contract - ); + let addrs = drop_helpers::get_contracts!(deps, config.factory_contract, puppeteer_contract); check_latest_icq_responses(deps.as_ref(), addrs.puppeteer_contract)?; From 25f18ae1ef0896acbc7b14b8c141673f87fae382 Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Mon, 11 Nov 2024 13:21:26 +0700 Subject: [PATCH 06/14] fix: review --- packages/helpers/src/phonebook.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/helpers/src/phonebook.rs b/packages/helpers/src/phonebook.rs index 478e6219..a0c5b542 100644 --- a/packages/helpers/src/phonebook.rs +++ b/packages/helpers/src/phonebook.rs @@ -20,7 +20,7 @@ macro_rules! get_contracts { Phonebook { $( $field_name: contracts.get(stringify!($field_name)) - .unwrap_or_else(|| panic!("Field {} not found in contracts", stringify!($field_name))) + .expect(&format!("{} contract not found", stringify!($field_name))) .to_string(), )* } From 5ef7422fd6c24d033736b69fa8b7ee04747e2525 Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Tue, 12 Nov 2024 00:32:06 +0700 Subject: [PATCH 07/14] fix: review --- contracts/core/src/contract.rs | 2 - contracts/factory/src/contract.rs | 153 +++++++---------- contracts/factory/src/lib.rs | 1 - contracts/factory/src/tests.rs | 161 ++++++++---------- .../base/src/error/factory.rs | 2 + packages/base/src/error/mod.rs | 1 + packages/base/src/msg/factory.rs | 6 +- packages/base/src/state/factory.rs | 36 +++- packages/helpers/src/phonebook.rs | 16 +- 9 files changed, 187 insertions(+), 191 deletions(-) rename contracts/factory/src/error.rs => packages/base/src/error/factory.rs (91%) diff --git a/contracts/core/src/contract.rs b/contracts/core/src/contract.rs index 16a52dde..505b268e 100644 --- a/contracts/core/src/contract.rs +++ b/contracts/core/src/contract.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use cosmwasm_schema::cw_serde; use cosmwasm_std::{ attr, ensure, ensure_eq, ensure_ne, to_json_binary, Addr, Attribute, BankQuery, Binary, Coin, diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 15c2918e..ccb7f204 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -1,11 +1,18 @@ use std::collections::HashMap; -use crate::error::ContractResult; use cosmwasm_std::{ attr, instantiate2_address, to_json_binary, Binary, CodeInfoResponse, CosmosMsg, Deps, DepsMut, - Env, HexBinary, MessageInfo, Response, StdResult, Uint128, WasmMsg, + Env, HexBinary, MessageInfo, Response, Uint128, WasmMsg, }; use drop_helpers::answer::response; +use drop_helpers::phonebook::{ + CORE_CONTRACT, DISTRIBUTION_CONTRACT, LSM_SHARE_BOND_PROVIDER_CONTRACT, + NATIVE_BOND_PROVIDER_CONTRACT, PUPPETEER_CONTRACT, REWARDS_MANAGER_CONTRACT, + REWARDS_PUMP_CONTRACT, SPLITTER_CONTRACT, STRATEGY_CONTRACT, TOKEN_CONTRACT, + VALIDATORS_SET_CONTRACT, WITHDRAWAL_MANAGER_CONTRACT, WITHDRAWAL_VOUCHER_CONTRACT, +}; +use drop_staking_base::error::factory::ContractResult; +use drop_staking_base::state::factory::Phonebook; use drop_staking_base::state::splitter::Config as SplitterConfig; use drop_staking_base::{ msg::factory::{ @@ -202,62 +209,35 @@ pub fn instantiate( deps.api.addr_humanize(&lsm_share_bond_provider_address)?; let native_bond_provider_contract = deps.api.addr_humanize(&native_bond_provider_address)?; - STATE.save(deps.storage, "token_contract".to_string(), &token_contract)?; - STATE.save(deps.storage, "core_contract".to_string(), &core_contract)?; - STATE.save( - deps.storage, - "puppeteer_contract".to_string(), - &puppeteer_contract, - )?; - STATE.save( - deps.storage, - "withdrawal_voucher_contract".to_string(), - &withdrawal_voucher_contract, - )?; - STATE.save( - deps.storage, - "withdrawal_manager_contract".to_string(), - &withdrawal_manager_contract, - )?; - STATE.save( - deps.storage, - "strategy_contract".to_string(), - &strategy_contract, - )?; - STATE.save( - deps.storage, - "validators_set_contract".to_string(), - &validators_set_contract, - )?; - STATE.save( - deps.storage, - "distribution_contract".to_string(), - &distribution_contract, - )?; - STATE.save( - deps.storage, - "rewards_manager_contract".to_string(), - &rewards_manager_contract, - )?; - STATE.save( - deps.storage, - "rewards_pump_contract".to_string(), - &rewards_pump_contract, - )?; - STATE.save( - deps.storage, - "splitter_contract".to_string(), - &splitter_contract, - )?; STATE.save( deps.storage, - "lsm_share_bond_provider_contract".to_string(), - &lsm_share_bond_provider_contract, - )?; - STATE.save( - deps.storage, - "native_bond_provider_contract".to_string(), - &native_bond_provider_contract, + &Phonebook::new([ + (CORE_CONTRACT, core_contract.clone()), + ( + WITHDRAWAL_MANAGER_CONTRACT, + withdrawal_manager_contract.clone(), + ), + (REWARDS_MANAGER_CONTRACT, rewards_manager_contract.clone()), + (TOKEN_CONTRACT, token_contract.clone()), + (PUPPETEER_CONTRACT, puppeteer_contract.clone()), + ( + WITHDRAWAL_VOUCHER_CONTRACT, + withdrawal_voucher_contract.clone(), + ), + (STRATEGY_CONTRACT, strategy_contract.clone()), + (VALIDATORS_SET_CONTRACT, validators_set_contract.clone()), + (DISTRIBUTION_CONTRACT, distribution_contract.clone()), + (SPLITTER_CONTRACT, splitter_contract.clone()), + ( + LSM_SHARE_BOND_PROVIDER_CONTRACT, + lsm_share_bond_provider_contract.clone(), + ), + ( + NATIVE_BOND_PROVIDER_CONTRACT, + native_bond_provider_contract.clone(), + ), + (REWARDS_PUMP_CONTRACT, rewards_pump_contract.clone()), + ]), )?; let msgs = vec![ @@ -469,7 +449,7 @@ pub fn instantiate( } #[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] -pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { +pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> ContractResult { match msg { QueryMsg::State {} => query_state(deps), QueryMsg::PauseInfo {} => query_pause_info(deps), @@ -481,27 +461,27 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult) -> StdResult { - let state = STATE - .range(deps.storage, None, None, cosmwasm_std::Order::Ascending) - .collect::>>()?; - to_json_binary(&state) +fn query_state(deps: Deps) -> ContractResult { + let state = STATE.load(deps.storage)?; + Ok(to_json_binary(&state.map)?) } -fn query_locate(deps: Deps, items: Vec) -> StdResult { +fn query_locate(deps: Deps, items: Vec) -> ContractResult { let mut contracts: HashMap = HashMap::new(); + let state = STATE.load(deps.storage)?; for item in items { - contracts.insert(item.clone(), STATE.load(deps.storage, item)?.to_string()); + let item_key = item.clone(); + let contract = state.get_as_result(&item_key)?; + contracts.insert(item.clone(), contract.to_string()); } - to_json_binary(&contracts) + Ok(to_json_binary(&contracts)?) } -fn query_pause_info(deps: Deps) -> StdResult { - let core_contract = STATE.load(deps.storage, "core_contract".to_string())?; - let withdrawal_manager_contract = - STATE.load(deps.storage, "withdrawal_manager_contract".to_string())?; - let rewards_manager_contract = - STATE.load(deps.storage, "rewards_manager_contract".to_string())?; +fn query_pause_info(deps: Deps) -> ContractResult { + let state = STATE.load(deps.storage)?; + let core_contract = state.get_as_result(CORE_CONTRACT)?; + let withdrawal_manager_contract = state.get_as_result(WITHDRAWAL_MANAGER_CONTRACT)?; + let rewards_manager_contract = state.get_as_result(REWARDS_MANAGER_CONTRACT)?; to_json_binary(&drop_staking_base::state::factory::PauseInfoResponse { core: deps @@ -544,11 +524,11 @@ pub fn execute( fn exec_pause(deps: DepsMut, info: MessageInfo) -> ContractResult> { cw_ownable::assert_owner(deps.storage, &info.sender)?; - let core_contract = STATE.load(deps.storage, "core_contract".to_string())?; - let rewards_manager_contract = - STATE.load(deps.storage, "rewards_manager_contract".to_string())?; - let withdrawal_manager_contract = - STATE.load(deps.storage, "withdrawal_manager_contract".to_string())?; + let state = STATE.load(deps.storage)?; + let core_contract = state.get_as_result(CORE_CONTRACT)?; + let withdrawal_manager_contract = state.get_as_result(WITHDRAWAL_MANAGER_CONTRACT)?; + let rewards_manager_contract = state.get_as_result(REWARDS_MANAGER_CONTRACT)?; + let attrs = vec![attr("action", "pause")]; let messages = vec![ get_proxied_message( @@ -578,11 +558,10 @@ fn exec_pause(deps: DepsMut, info: MessageInfo) -> ContractResult ContractResult> { cw_ownable::assert_owner(deps.storage, &info.sender)?; - let core_contract = STATE.load(deps.storage, "core_contract".to_string())?; - let rewards_manager_contract = - STATE.load(deps.storage, "rewards_manager_contract".to_string())?; - let withdrawal_manager_contract = - STATE.load(deps.storage, "withdrawal_manager_contract".to_string())?; + let state = STATE.load(deps.storage)?; + let core_contract = state.get_as_result(CORE_CONTRACT)?; + let withdrawal_manager_contract = state.get_as_result(WITHDRAWAL_MANAGER_CONTRACT)?; + let rewards_manager_contract = state.get_as_result(REWARDS_MANAGER_CONTRACT)?; let attrs = vec![attr("action", "unpause")]; let messages = vec![ get_proxied_message( @@ -629,9 +608,9 @@ fn execute_update_config( ) -> ContractResult> { let attrs = vec![attr("action", "update-config")]; cw_ownable::assert_owner(deps.storage, &info.sender)?; - let core_contract = STATE.load(deps.storage, "core_contract".to_string())?; - let validators_set_contract = - STATE.load(deps.storage, "validators_set_contract".to_string())?; + let state = STATE.load(deps.storage)?; + let core_contract = state.get_as_result(CORE_CONTRACT)?; + let validators_set_contract = state.get_as_result(VALIDATORS_SET_CONTRACT)?; let mut messages = vec![]; match msg { UpdateConfigMsg::Core(msg) => messages.push(get_proxied_message( @@ -656,9 +635,9 @@ fn execute_proxy_msg( info: MessageInfo, msg: ProxyMsg, ) -> ContractResult> { - let validators_set_contract = - STATE.load(deps.storage, "validators_set_contract".to_string())?; - let puppeteer_contract = STATE.load(deps.storage, "puppeteer_contract".to_string())?; + let state = STATE.load(deps.storage)?; + let validators_set_contract = state.get_as_result(VALIDATORS_SET_CONTRACT)?; + let puppeteer_contract = state.get_as_result(PUPPETEER_CONTRACT)?; let mut messages = vec![]; let attrs = vec![attr("action", "proxy-call")]; cw_ownable::assert_owner(deps.storage, &info.sender)?; diff --git a/contracts/factory/src/lib.rs b/contracts/factory/src/lib.rs index 19b07e61..1b4b5763 100644 --- a/contracts/factory/src/lib.rs +++ b/contracts/factory/src/lib.rs @@ -1,4 +1,3 @@ pub mod contract; -pub mod error; #[cfg(test)] pub mod tests; diff --git a/contracts/factory/src/tests.rs b/contracts/factory/src/tests.rs index ffa8a68b..ea5beccb 100644 --- a/contracts/factory/src/tests.rs +++ b/contracts/factory/src/tests.rs @@ -4,13 +4,21 @@ use cosmwasm_std::{ testing::{mock_env, mock_info}, to_json_binary, Addr, BankMsg, DepsMut, Uint128, }; -use drop_helpers::testing::{mock_dependencies, mock_dependencies_with_api}; +use drop_helpers::{ + phonebook::{ + CORE_CONTRACT, DISTRIBUTION_CONTRACT, LSM_SHARE_BOND_PROVIDER_CONTRACT, + NATIVE_BOND_PROVIDER_CONTRACT, PUPPETEER_CONTRACT, REWARDS_MANAGER_CONTRACT, + REWARDS_PUMP_CONTRACT, SPLITTER_CONTRACT, STRATEGY_CONTRACT, TOKEN_CONTRACT, + VALIDATORS_SET_CONTRACT, WITHDRAWAL_MANAGER_CONTRACT, WITHDRAWAL_VOUCHER_CONTRACT, + }, + testing::{mock_dependencies, mock_dependencies_with_api}, +}; use drop_staking_base::{ msg::factory::{ CoreParams, ExecuteMsg, FeeParams, InstantiateMsg, LsmShareBondParams, NativeBondParams, QueryMsg, UpdateConfigMsg, ValidatorSetMsg, }, - state::factory::{CodeIds, RemoteOpts, Timeout, STATE}, + state::factory::{CodeIds, Phonebook, RemoteOpts, Timeout, STATE}, }; use drop_staking_base::{ msg::{ @@ -44,92 +52,45 @@ fn set_default_factory_state(deps: DepsMut) { STATE .save( deps.storage, - "token_contract".to_string(), - &Addr::unchecked("token_contract".to_string()), - ) - .unwrap(); - STATE - .save( - deps.storage, - "core_contract".to_string(), - &Addr::unchecked("core_contract".to_string()), - ) - .unwrap(); - STATE - .save( - deps.storage, - "puppeteer_contract".to_string(), - &Addr::unchecked("puppeteer_contract".to_string()), - ) - .unwrap(); - STATE - .save( - deps.storage, - "withdrawal_voucher_contract".to_string(), - &Addr::unchecked("withdrawal_voucher_contract".to_string()), - ) - .unwrap(); - STATE - .save( - deps.storage, - "withdrawal_manager_contract".to_string(), - &Addr::unchecked("withdrawal_manager_contract".to_string()), - ) - .unwrap(); - STATE - .save( - deps.storage, - "strategy_contract".to_string(), - &Addr::unchecked("strategy_contract".to_string()), - ) - .unwrap(); - STATE - .save( - deps.storage, - "validators_set_contract".to_string(), - &Addr::unchecked("validators_set_contract".to_string()), - ) - .unwrap(); - STATE - .save( - deps.storage, - "distribution_contract".to_string(), - &Addr::unchecked("distribution_contract".to_string()), - ) - .unwrap(); - STATE - .save( - deps.storage, - "rewards_manager_contract".to_string(), - &Addr::unchecked("rewards_manager_contract".to_string()), - ) - .unwrap(); - STATE - .save( - deps.storage, - "rewards_pump_contract".to_string(), - &Addr::unchecked("rewards_pump_contract".to_string()), - ) - .unwrap(); - STATE - .save( - deps.storage, - "splitter_contract".to_string(), - &Addr::unchecked("splitter_contract".to_string()), - ) - .unwrap(); - STATE - .save( - deps.storage, - "lsm_share_bond_provider_contract".to_string(), - &Addr::unchecked("lsm_share_bond_provider_contract".to_string()), - ) - .unwrap(); - STATE - .save( - deps.storage, - "native_bond_provider_contract".to_string(), - &Addr::unchecked("native_bond_provider_contract".to_string()), + &Phonebook::new([ + (TOKEN_CONTRACT, Addr::unchecked("token_contract")), + (CORE_CONTRACT, Addr::unchecked("core_contract")), + (PUPPETEER_CONTRACT, Addr::unchecked("puppeteer_contract")), + ( + WITHDRAWAL_MANAGER_CONTRACT, + Addr::unchecked("withdrawal_manager_contract"), + ), + ( + WITHDRAWAL_VOUCHER_CONTRACT, + Addr::unchecked("withdrawal_voucher_contract"), + ), + (STRATEGY_CONTRACT, Addr::unchecked("strategy_contract")), + ( + VALIDATORS_SET_CONTRACT, + Addr::unchecked("validators_set_contract"), + ), + ( + DISTRIBUTION_CONTRACT, + Addr::unchecked("distribution_contract"), + ), + ( + REWARDS_MANAGER_CONTRACT, + Addr::unchecked("rewards_manager_contract"), + ), + ( + REWARDS_PUMP_CONTRACT, + Addr::unchecked("rewards_pump_contract"), + ), + (SPLITTER_CONTRACT, Addr::unchecked("splitter_contract")), + ( + LSM_SHARE_BOND_PROVIDER_CONTRACT, + Addr::unchecked("lsm_share_bond_provider_contract"), + ), + ( + NATIVE_BOND_PROVIDER_CONTRACT, + Addr::unchecked("native_bond_provider_contract"), + ), + ]), ) .unwrap(); } @@ -629,7 +590,9 @@ fn test_update_config_core_unauthorized() { .unwrap_err(); assert_eq!( res, - crate::error::ContractError::OwnershipError(cw_ownable::OwnershipError::NotOwner) + drop_staking_base::error::factory::ContractError::OwnershipError( + cw_ownable::OwnershipError::NotOwner + ) ); } @@ -705,7 +668,9 @@ fn test_update_config_validators_set_unauthorized() { .unwrap_err(); assert_eq!( res, - crate::error::ContractError::OwnershipError(cw_ownable::OwnershipError::NotOwner) + drop_staking_base::error::factory::ContractError::OwnershipError( + cw_ownable::OwnershipError::NotOwner + ) ); } @@ -782,7 +747,9 @@ fn test_proxy_validators_set_update_validators_unauthorized() { .unwrap_err(); assert_eq!( res, - crate::error::ContractError::OwnershipError(cw_ownable::OwnershipError::NotOwner) + drop_staking_base::error::factory::ContractError::OwnershipError( + cw_ownable::OwnershipError::NotOwner + ) ); } @@ -905,7 +872,9 @@ fn test_admin_execute_unauthorized() { .unwrap_err(); assert_eq!( res, - crate::error::ContractError::OwnershipError(cw_ownable::OwnershipError::NotOwner) + drop_staking_base::error::factory::ContractError::OwnershipError( + cw_ownable::OwnershipError::NotOwner + ) ); } @@ -1000,7 +969,9 @@ fn test_pause_unauthorized() { .unwrap_err(); assert_eq!( res, - crate::error::ContractError::OwnershipError(cw_ownable::OwnershipError::NotOwner) + drop_staking_base::error::factory::ContractError::OwnershipError( + cw_ownable::OwnershipError::NotOwner + ) ); } @@ -1074,7 +1045,9 @@ fn test_unpause_unauthorized() { .unwrap_err(); assert_eq!( res, - crate::error::ContractError::OwnershipError(cw_ownable::OwnershipError::NotOwner) + drop_staking_base::error::factory::ContractError::OwnershipError( + cw_ownable::OwnershipError::NotOwner + ) ); } diff --git a/contracts/factory/src/error.rs b/packages/base/src/error/factory.rs similarity index 91% rename from contracts/factory/src/error.rs rename to packages/base/src/error/factory.rs index 18be32b1..a3648fdb 100644 --- a/contracts/factory/src/error.rs +++ b/packages/base/src/error/factory.rs @@ -26,6 +26,8 @@ pub enum ContractError { Unknown {}, #[error("Semver parsing error: {0}")] SemVer(String), + #[error("Contract address not found: {name}")] + ContractAddressNotFound { name: String }, } impl From for ContractError { diff --git a/packages/base/src/error/mod.rs b/packages/base/src/error/mod.rs index c3b1a628..7abfee6a 100644 --- a/packages/base/src/error/mod.rs +++ b/packages/base/src/error/mod.rs @@ -1,6 +1,7 @@ pub mod astroport_exchange_handler; pub mod core; pub mod distribution; +pub mod factory; pub mod lsm_share_bond_provider; pub mod mirror; pub mod native_bond_provider; diff --git a/packages/base/src/msg/factory.rs b/packages/base/src/msg/factory.rs index d4137cf5..cb28449c 100644 --- a/packages/base/src/msg/factory.rs +++ b/packages/base/src/msg/factory.rs @@ -5,8 +5,6 @@ use cosmwasm_std::{CosmosMsg, Decimal, Uint128}; use cw_ownable::cw_ownable_execute; use drop_macros::pausable; use neutron_sdk::bindings::msg::NeutronMsg; -#[allow(unused_imports)] -use std::collections::HashMap; #[cw_serde] pub struct InstantiateMsg { @@ -86,9 +84,9 @@ pub struct MigrateMsg {} #[cw_serde] #[derive(QueryResponses)] pub enum QueryMsg { - #[returns(HashMap)] + #[returns(std::collections::HashMap)] State {}, - #[returns(HashMap)] + #[returns(std::collections::HashMap)] Locate { contracts: Vec }, #[returns(crate::state::factory::PauseInfoResponse)] PauseInfo {}, diff --git a/packages/base/src/state/factory.rs b/packages/base/src/state/factory.rs index eaf05791..d832823b 100644 --- a/packages/base/src/state/factory.rs +++ b/packages/base/src/state/factory.rs @@ -1,6 +1,7 @@ use cosmwasm_schema::cw_serde; use cosmwasm_std::Addr; -use cw_storage_plus::Map; +use cw_storage_plus::Item; +use std::hash::Hash; #[cw_serde] pub struct CodeIds { @@ -43,4 +44,35 @@ pub struct PauseInfoResponse { pub rewards_manager: drop_helpers::pause::PauseInfoResponse, } -pub const STATE: Map = Map::new("state"); +#[cw_serde] +pub struct Phonebook { + pub map: std::collections::HashMap, +} + +pub const STATE: Item = Item::new("state"); + +impl Phonebook { + pub fn get_as_result<'a>( + &'a self, + key: &'a str, + ) -> Result<&Addr, crate::error::factory::ContractError> { + self.map.get(key).ok_or( + crate::error::factory::ContractError::ContractAddressNotFound { + name: key.to_string(), + }, + ) + } + + pub fn new(arr: [(K, Addr); N]) -> Self + where + // Bounds from impl: + K: Eq + Hash + Into + Clone + std::fmt::Display, + { + let map = arr + .iter() + .clone() + .map(|(k, v)| (k.to_string(), v.clone())) + .collect(); + Self { map } + } +} diff --git a/packages/helpers/src/phonebook.rs b/packages/helpers/src/phonebook.rs index a0c5b542..b8f5786e 100644 --- a/packages/helpers/src/phonebook.rs +++ b/packages/helpers/src/phonebook.rs @@ -10,7 +10,7 @@ macro_rules! get_contracts { } let contracts = $deps .querier - .query::>(&QueryRequest::Wasm(WasmQuery::Smart { + .query::>(&QueryRequest::Wasm(WasmQuery::Smart { contract_addr: $factory_contract.to_string(), msg: to_json_binary(&drop_staking_base::msg::factory::QueryMsg::Locate { contracts: vec![$(stringify!($field_name).to_string()),*], @@ -27,3 +27,17 @@ macro_rules! get_contracts { } }; } + +pub const CORE_CONTRACT: &str = "core_contract"; +pub const WITHDRAWAL_MANAGER_CONTRACT: &str = "withdrawal_manager_contract"; +pub const REWARDS_MANAGER_CONTRACT: &str = "rewards_manager_contract"; +pub const TOKEN_CONTRACT: &str = "token_contract"; +pub const PUPPETEER_CONTRACT: &str = "puppeteer_contract"; +pub const WITHDRAWAL_VOUCHER_CONTRACT: &str = "withdrawal_voucher_contract"; +pub const STRATEGY_CONTRACT: &str = "strategy_contract"; +pub const VALIDATORS_SET_CONTRACT: &str = "validators_set_contract"; +pub const DISTRIBUTION_CONTRACT: &str = "distribution_contract"; +pub const REWARDS_PUMP_CONTRACT: &str = "rewards_pump_contract"; +pub const SPLITTER_CONTRACT: &str = "splitter_contract"; +pub const LSM_SHARE_BOND_PROVIDER_CONTRACT: &str = "lsm_share_bond_provider_contract"; +pub const NATIVE_BOND_PROVIDER_CONTRACT: &str = "native_bond_provider_contract"; From 2a988e87681116262539f51aba5e947a02fc8a63 Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Mon, 25 Nov 2024 13:50:44 +0100 Subject: [PATCH 08/14] wip --- Cargo.lock | 34 + Cargo.toml | 2 + contracts/icq-adapter-kv/.cargo/config | 2 + contracts/icq-adapter-kv/Cargo.toml | 36 + contracts/icq-adapter-kv/README.md | 1 + .../src/bin/drop-icq-router-schema.rs | 10 + contracts/icq-adapter-kv/src/contract.rs | 173 +++++ contracts/icq-adapter-kv/src/lib.rs | 5 + contracts/icq-adapter-kv/src/msg.rs | 4 + contracts/icq-adapter-kv/src/tests.rs | 645 ++++++++++++++++++ contracts/icq-router/.cargo/config | 2 + contracts/icq-router/Cargo.toml | 36 + contracts/icq-router/README.md | 1 + .../src/bin/drop-icq-router-schema.rs | 10 + contracts/icq-router/src/contract.rs | 173 +++++ contracts/icq-router/src/lib.rs | 4 + contracts/icq-router/src/tests.rs | 645 ++++++++++++++++++ contracts/puppeteer-authz/src/msg.rs | 1 - packages/base/src/error/icq_adapter.rs | 26 + packages/base/src/error/icq_router.rs | 29 + packages/base/src/error/mod.rs | 2 + packages/base/src/msg/icq_adapter.rs | 29 + packages/base/src/msg/icq_router.rs | 72 ++ packages/base/src/msg/mod.rs | 3 +- packages/base/src/msg/puppeteer.rs | 1 - packages/base/src/state/icq_adapter.rs | 21 + packages/base/src/state/icq_router.rs | 20 + packages/base/src/state/mod.rs | 2 + packages/puppeteer-base/src/execute.rs | 18 - packages/puppeteer-base/src/msg.rs | 1 - ts-client/lib/contractLib/dropCore.d.ts | 22 +- ts-client/lib/contractLib/dropFactory.d.ts | 8 +- ts-client/src/contractLib/dropCore.ts | 22 +- ts-client/src/contractLib/dropFactory.ts | 8 +- 34 files changed, 1994 insertions(+), 74 deletions(-) create mode 100644 contracts/icq-adapter-kv/.cargo/config create mode 100644 contracts/icq-adapter-kv/Cargo.toml create mode 100644 contracts/icq-adapter-kv/README.md create mode 100644 contracts/icq-adapter-kv/src/bin/drop-icq-router-schema.rs create mode 100644 contracts/icq-adapter-kv/src/contract.rs create mode 100644 contracts/icq-adapter-kv/src/lib.rs create mode 100644 contracts/icq-adapter-kv/src/msg.rs create mode 100644 contracts/icq-adapter-kv/src/tests.rs create mode 100644 contracts/icq-router/.cargo/config create mode 100644 contracts/icq-router/Cargo.toml create mode 100644 contracts/icq-router/README.md create mode 100644 contracts/icq-router/src/bin/drop-icq-router-schema.rs create mode 100644 contracts/icq-router/src/contract.rs create mode 100644 contracts/icq-router/src/lib.rs create mode 100644 contracts/icq-router/src/tests.rs create mode 100644 packages/base/src/error/icq_adapter.rs create mode 100644 packages/base/src/error/icq_router.rs create mode 100644 packages/base/src/msg/icq_adapter.rs create mode 100644 packages/base/src/msg/icq_router.rs create mode 100644 packages/base/src/state/icq_adapter.rs create mode 100644 packages/base/src/state/icq_router.rs diff --git a/Cargo.lock b/Cargo.lock index fd2e8edf..5614a665 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -721,6 +721,40 @@ dependencies = [ "thiserror", ] +[[package]] +name = "drop-icq-adapter-kv" +version = "1.0.0" +dependencies = [ + "bech32 0.11.0", + "cosmwasm-schema", + "cosmwasm-std", + "cw-ownable", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw2 1.1.2", + "drop-helpers", + "drop-staking-base", + "neutron-sdk", + "semver", +] + +[[package]] +name = "drop-icq-router" +version = "1.0.0" +dependencies = [ + "bech32 0.11.0", + "cosmwasm-schema", + "cosmwasm-std", + "cw-ownable", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw2 1.1.2", + "drop-helpers", + "drop-staking-base", + "neutron-sdk", + "semver", +] + [[package]] name = "drop-lsm-share-bond-provider" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index 2fc167b5..62f7daab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,8 +25,10 @@ members = [ "contracts/mirror", "contracts/price-provider", "contracts/validators-stats", + "contracts/icq-adapter-kv", "contracts/validators-set", "contracts/redemption-rate-adapter", + "contracts/icq-router", "packages/base", "packages/helpers", "packages/macros", diff --git a/contracts/icq-adapter-kv/.cargo/config b/contracts/icq-adapter-kv/.cargo/config new file mode 100644 index 00000000..5d2a9bf7 --- /dev/null +++ b/contracts/icq-adapter-kv/.cargo/config @@ -0,0 +1,2 @@ +[alias] +schema = "run --bin drop-mirror-schema" diff --git a/contracts/icq-adapter-kv/Cargo.toml b/contracts/icq-adapter-kv/Cargo.toml new file mode 100644 index 00000000..a582498c --- /dev/null +++ b/contracts/icq-adapter-kv/Cargo.toml @@ -0,0 +1,36 @@ +[package] +authors = ["Sergey Ratiashvili "] +description = "KV adapter for ICQ" +edition = "2021" +name = "drop-icq-adapter-kv" +version = "1.0.0" + +exclude = [ + # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. + "contract.wasm", + "hash.txt", +] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +# for more explicit tests, cargo test --features=backtraces +backtraces = ["cosmwasm-std/backtraces"] +# use library feature to disable all instantiate/execute/query exports +library = [] + +[dependencies] +cosmwasm-schema = { workspace = true } +cosmwasm-std = { workspace = true } +cw-ownable = { workspace = true } +cw2 = { workspace = true } +neutron-sdk = { workspace = true } +drop-staking-base = { workspace = true } +drop-helpers = { workspace = true } +semver = { workspace = true } +cw-storage-plus = { workspace = true } +cw-utils = { workspace = true } +bech32 = { workspace = true } diff --git a/contracts/icq-adapter-kv/README.md b/contracts/icq-adapter-kv/README.md new file mode 100644 index 00000000..29381110 --- /dev/null +++ b/contracts/icq-adapter-kv/README.md @@ -0,0 +1 @@ +# DROP Mirror contract \ No newline at end of file diff --git a/contracts/icq-adapter-kv/src/bin/drop-icq-router-schema.rs b/contracts/icq-adapter-kv/src/bin/drop-icq-router-schema.rs new file mode 100644 index 00000000..0667282c --- /dev/null +++ b/contracts/icq-adapter-kv/src/bin/drop-icq-router-schema.rs @@ -0,0 +1,10 @@ +use cosmwasm_schema::write_api; +use drop_staking_base::msg::icq_router::{ExecuteMsg, InstantiateMsg, QueryMsg}; + +fn main() { + write_api! { + instantiate: InstantiateMsg, + query: QueryMsg, + execute: ExecuteMsg + } +} diff --git a/contracts/icq-adapter-kv/src/contract.rs b/contracts/icq-adapter-kv/src/contract.rs new file mode 100644 index 00000000..44916ac9 --- /dev/null +++ b/contracts/icq-adapter-kv/src/contract.rs @@ -0,0 +1,173 @@ +use cosmwasm_std::{ + attr, ensure, ensure_eq, to_json_binary, Binary, CosmosMsg, Deps, DepsMut, Env, MessageInfo, + Response, WasmMsg, +}; +use drop_helpers::answer::response; +use drop_staking_base::msg::icq_router::{BalancesData, DelegationsData}; +use drop_staking_base::state::icq_adapter::{Config, ConfigOptional, CONFIG}; +use drop_staking_base::{ + error::icq_adapter::{ContractError, ContractResult}, + msg::icq_adapter::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}, +}; +use neutron_sdk::bindings::{msg::NeutronMsg, query::NeutronQuery}; + +use std::{env, vec}; + +use crate::msg::Options; + +const CONTRACT_NAME: &str = concat!("crates.io:drop-staking__", env!("CARGO_PKG_NAME")); +const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] +pub fn instantiate( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: InstantiateMsg, +) -> ContractResult> { + let owner = msg.owner.unwrap_or(info.sender.to_string()); + cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + cw_ownable::initialize_owner(deps.storage, deps.api, Some(owner.as_str()))?; + let router = deps.api.addr_validate(&msg.router)?; + let attrs = vec![ + attr("action", "instantiate"), + attr("router", router.to_string()), + attr("owner", owner), + ]; + CONFIG.save(deps.storage, &Config { router })?; + Ok(response("instantiate", CONTRACT_NAME, attrs)) +} + +#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] +pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> ContractResult { + match msg { + QueryMsg::Balances {} => query_balance(deps), + QueryMsg::Delegations {} => query_delegations(deps), + QueryMsg::NonNativeRewardsBalances {} => query_non_native_rewards_balances(deps), + QueryMsg::Ownership {} => Ok(to_json_binary(&cw_ownable::get_ownership(deps.storage)?)?), + QueryMsg::Config {} => Ok(to_json_binary(&CONFIG.load(deps.storage)?)?), + } +} + +#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] +pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> ContractResult> { + match msg { + ExecuteMsg::UpdateValidators { validators } => { + update_validators(deps, info, env, validators) + } + ExecuteMsg::UpdateConfig { new_config } => update_config(deps, info, new_config), + ExecuteMsg::UpdateOwnership(action) => { + let attrs = vec![attr("action", "update_ownership")]; + cw_ownable::update_ownership(deps.into_empty(), &env.block, &info.sender, action)?; + Ok(response("update_ownership", CONTRACT_NAME, attrs)) + } + ExecuteMsg::UpdateBalances { balances } => update_balances(deps, info, env, balances), + ExecuteMsg::UpdateDelegations { delegations } => { + update_delegations(deps, info, env, delegations) + } + } +} + +#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] +pub fn migrate( + deps: DepsMut, + _env: Env, + _msg: MigrateMsg, +) -> ContractResult> { + let version: semver::Version = CONTRACT_VERSION.parse()?; + let storage_version: semver::Version = + cw2::get_contract_version(deps.storage)?.version.parse()?; + if storage_version < version { + cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + } + Ok(Response::new()) +} + +fn query_balance(deps: Deps) -> ContractResult { + let balance = BALANCES.load(deps.storage)?; + Ok(to_json_binary(&balance)?) +} + +fn query_delegations(deps: Deps) -> ContractResult { + let delegations = DELEGATIONS.load(deps.storage)?; + Ok(to_json_binary(&delegations)?) +} + +fn query_non_native_rewards_balances(deps: Deps) -> ContractResult { + let balances = NON_NATIVE_REWARD_BALANCES.load(deps.storage)?; + Ok(to_json_binary(&balances)?) +} + +fn update_balances( + deps: DepsMut, + info: MessageInfo, + _env: Env, + balances: BalancesData, +) -> ContractResult> { + let config = CONFIG.load(deps.storage)?; + ensure_eq!(info.sender, config.adapter, ContractError::Unauthorized {}); + let old_data = BALANCES.load(deps.storage)?; + ensure!( + balances.remote_height > old_data.remote_height, + ContractError::OutdatedData + ); + BALANCES.save(deps.storage, &balances)?; + Ok(Response::new()) +} + +fn update_config( + deps: DepsMut, + info: MessageInfo, + new_config: ConfigOptional, +) -> ContractResult> { + cw_ownable::assert_owner(deps.storage, &info.sender)?; + let mut config = CONFIG.load(deps.storage)?; + if let Some(adapter) = new_config.adapter { + config.adapter = deps.api.addr_validate(&adapter)?; + } + CONFIG.save(deps.storage, &config)?; + Ok(Response::new()) +} + +fn update_delegations( + deps: DepsMut, + info: MessageInfo, + _env: Env, + delegations: DelegationsData, +) -> ContractResult> { + let config = CONFIG.load(deps.storage)?; + ensure_eq!(info.sender, config.adapter, ContractError::Unauthorized {}); + let old_data = DELEGATIONS.load(deps.storage)?; + ensure!( + delegations.remote_height > old_data.remote_height, + ContractError::OutdatedData + ); + DELEGATIONS.save(deps.storage, &delegations)?; + Ok(Response::new()) +} + +fn update_validators( + deps: DepsMut, + _info: MessageInfo, + _env: Env, + validators: Vec, +) -> ContractResult> { + let config = CONFIG.load(deps.storage)?; + let res = response( + "update_validators", + CONTRACT_NAME, + [attr("validators", format!("{:?}", validators))], + ); + Ok(res.add_message(CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: config.adapter.to_string(), + msg: to_json_binary( + &drop_staking_base::msg::icq_adapter::ExecuteMsg::UpdateValidatorSet { validators }, + )?, + funds: vec![], + }))) +} diff --git a/contracts/icq-adapter-kv/src/lib.rs b/contracts/icq-adapter-kv/src/lib.rs new file mode 100644 index 00000000..fbedb827 --- /dev/null +++ b/contracts/icq-adapter-kv/src/lib.rs @@ -0,0 +1,5 @@ +pub mod contract; +pub mod msg; + +// #[cfg(test)] +// mod tests; diff --git a/contracts/icq-adapter-kv/src/msg.rs b/contracts/icq-adapter-kv/src/msg.rs new file mode 100644 index 00000000..aa184185 --- /dev/null +++ b/contracts/icq-adapter-kv/src/msg.rs @@ -0,0 +1,4 @@ +use cosmwasm_schema::cw_serde; + +#[cw_serde] +pub struct Options {} diff --git a/contracts/icq-adapter-kv/src/tests.rs b/contracts/icq-adapter-kv/src/tests.rs new file mode 100644 index 00000000..c6bc0a41 --- /dev/null +++ b/contracts/icq-adapter-kv/src/tests.rs @@ -0,0 +1,645 @@ +use cosmwasm_std::{ + attr, coin, + testing::{mock_env, mock_info}, + to_json_binary, Addr, CosmosMsg, CustomQuery, DepsMut, Uint128, WasmMsg, +}; +use drop_helpers::testing::mock_dependencies; +use drop_staking_base::state::mirror::{BONDS, CONFIG, COUNTER}; +use neutron_sdk::{ + bindings::msg::{IbcFee, NeutronMsg}, + query::min_ibc_fee::MinIbcFeeResponse, + sudo::msg::RequestPacketTimeoutHeight, +}; + +fn base_init(deps: DepsMut) +where + T: CustomQuery, +{ + let config = drop_staking_base::state::mirror::Config { + core_contract: "core".to_string(), + source_port: "source_port".to_string(), + source_channel: "source_channel".to_string(), + ibc_timeout: 10, + prefix: "prefix".to_string(), + }; + CONFIG.save(deps.storage, &config).unwrap(); + COUNTER.save(deps.storage, &0).unwrap(); + cw_ownable::initialize_owner(deps.storage, deps.api, Some("owner")).unwrap(); +} + +#[test] +fn test_instantiate() { + let mut deps = mock_dependencies(&[]); + let response = crate::contract::instantiate( + deps.as_mut(), + mock_env(), + mock_info("sender", &[]), + drop_staking_base::msg::mirror::InstantiateMsg { + core_contract: "core".to_string(), + source_port: "source_port".to_string(), + source_channel: "source_channel".to_string(), + ibc_timeout: 10, + owner: Some("owner".to_string()), + prefix: "prefix".to_string(), + }, + ) + .unwrap(); + assert_eq!( + response, + cosmwasm_std::Response::new().add_event( + cosmwasm_std::Event::new("crates.io:drop-staking__drop-mirror-instantiate".to_string()) + .add_attributes(vec![attr("action", "instantiate"), attr("owner", "owner")]) + ) + ); + let config = CONFIG.load(&deps.storage).unwrap(); + assert_eq!( + config, + drop_staking_base::state::mirror::Config { + core_contract: "core".to_string(), + source_port: "source_port".to_string(), + source_channel: "source_channel".to_string(), + ibc_timeout: 10, + prefix: "prefix".to_string(), + } + ); + let owner = cw_ownable::get_ownership(&deps.storage).unwrap(); + assert_eq!(owner.owner, Some(Addr::unchecked("owner"))); + let counter = COUNTER.load(&deps.storage).unwrap(); + assert_eq!(counter, 0); +} + +#[test] +fn test_instantiate_wo_owner() { + let mut deps = mock_dependencies(&[]); + let response = crate::contract::instantiate( + deps.as_mut(), + mock_env(), + mock_info("sender", &[]), + drop_staking_base::msg::mirror::InstantiateMsg { + core_contract: "core".to_string(), + source_port: "source_port".to_string(), + source_channel: "source_channel".to_string(), + ibc_timeout: 10, + owner: None, + prefix: "prefix".to_string(), + }, + ) + .unwrap(); + assert_eq!( + response, + cosmwasm_std::Response::new().add_event( + cosmwasm_std::Event::new("crates.io:drop-staking__drop-mirror-instantiate".to_string()) + .add_attributes(vec![attr("action", "instantiate"), attr("owner", "sender")]) + ) + ); + let config = CONFIG.load(&deps.storage).unwrap(); + assert_eq!( + config, + drop_staking_base::state::mirror::Config { + core_contract: "core".to_string(), + source_port: "source_port".to_string(), + source_channel: "source_channel".to_string(), + ibc_timeout: 10, + prefix: "prefix".to_string(), + } + ); + let owner = cw_ownable::get_ownership(&deps.storage).unwrap(); + assert_eq!(owner.owner, Some(Addr::unchecked("sender"))); +} + +#[test] +fn update_config() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("owner", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::UpdateConfig { + new_config: drop_staking_base::state::mirror::ConfigOptional { + core_contract: Some("new_core".to_string()), + source_port: Some("new_source_port".to_string()), + source_channel: Some("new_source_channel".to_string()), + ibc_timeout: Some(20), + prefix: Some("new_prefix".to_string()), + }, + }, + ) + .unwrap(); + assert_eq!( + response, + cosmwasm_std::Response::new().add_event( + cosmwasm_std::Event::new( + "crates.io:drop-staking__drop-mirror-update_config".to_string() + ) + .add_attributes(vec![ + attr("action", "update_config"), + attr("core_contract", "new_core"), + attr("source_port", "new_source_port"), + attr("source_channel", "new_source_channel"), + attr("ibc_timeout", "20"), + attr("prefix", "new_prefix"), + ]) + ) + ); + let config = CONFIG.load(&deps.storage).unwrap(); + assert_eq!( + config, + drop_staking_base::state::mirror::Config { + core_contract: "new_core".to_string(), + source_port: "new_source_port".to_string(), + source_channel: "new_source_channel".to_string(), + ibc_timeout: 20, + prefix: "new_prefix".to_string(), + } + ); +} + +#[test] +fn bond_wrong_receiver() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("sender", &[coin(1000, "mytoken")]), + drop_staking_base::msg::mirror::ExecuteMsg::Bond { + receiver: "some".to_string(), + r#ref: Some("reff".to_string()), + backup: Some("backup".to_string()), + }, + ); + assert_eq!( + response, + Err(drop_staking_base::error::mirror::ContractError::InvalidPrefix {}) + ); +} + +#[test] +fn bond_no_funds() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("sender", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::Bond { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + r#ref: Some("reff".to_string()), + backup: Some("backup".to_string()), + }, + ); + assert_eq!( + response, + Err( + drop_staking_base::error::mirror::ContractError::PaymentError( + cw_utils::PaymentError::NoFunds {} + ) + ) + ); +} + +#[test] +fn bond() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("sender", &[coin(1000, "mytoken")]), + drop_staking_base::msg::mirror::ExecuteMsg::Bond { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + r#ref: Some("reff".to_string()), + backup: Some("backup".to_string()), + }, + ) + .unwrap(); + let counter = COUNTER.load(&deps.storage).unwrap(); + assert_eq!(counter, 1); + let bond = BONDS.load(&deps.storage, 1).unwrap(); + assert_eq!( + bond, + drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Initiated, + } + ); + assert_eq!( + response, + cosmwasm_std::Response::new() + .add_submessage(cosmwasm_std::SubMsg::reply_on_success( + WasmMsg::Execute { + contract_addr: "core".to_string(), + msg: to_json_binary(&drop_staking_base::msg::core::ExecuteMsg::Bond { + receiver: None, + r#ref: Some("reff".to_string()) + }) + .unwrap(), + funds: vec![coin(1000, "mytoken")], + }, + 1 + )) + .add_event( + cosmwasm_std::Event::new("crates.io:drop-staking__drop-mirror-bond".to_string()) + .add_attributes(vec![ + attr("action", "bond"), + attr("id", "1"), + attr( + "receiver", + "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + ), + attr("ref", "reff"), + attr("backup", "backup"), + ]) + ) + ); +} + +#[test] +fn complete_remote() { + let mut deps = mock_dependencies(&[]); + deps.querier.add_custom_query_response(|_| { + to_json_binary(&MinIbcFeeResponse { + min_fee: get_standard_fees(), + }) + .unwrap() + }); + base_init(deps.as_mut()); + BONDS + .save( + deps.as_mut().storage, + 1, + &drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: Some(coin(1000, "ld_denom")), + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Bonded, + }, + ) + .unwrap(); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("owner", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::Complete { items: vec![1] }, + ) + .unwrap(); + let bond = BONDS.load(&deps.storage, 1).unwrap(); + assert_eq!( + bond, + drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: Some(coin(1000, "ld_denom")), + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Sent, + } + ); + assert_eq!( + response, + cosmwasm_std::Response::new() + .add_submessage(cosmwasm_std::SubMsg::new(CosmosMsg::Custom( + NeutronMsg::IbcTransfer { + source_port: "source_port".to_string(), + source_channel: "source_channel".to_string(), + token: coin(1000, "ld_denom"), + sender: "cosmos2contract".to_string(), + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + timeout_height: RequestPacketTimeoutHeight { + revision_number: None, + revision_height: None + }, + timeout_timestamp: 1571797429879305533, + memo: "1".to_string(), + fee: get_standard_fees(), + } + ))) + .add_event( + cosmwasm_std::Event::new( + "crates.io:drop-staking__drop-mirror-complete".to_string() + ) + .add_attributes(vec![ + attr("action", "complete"), + attr("id", "1"), + attr("return_type", "Bonded"), + attr("coin", "1000ld_denom"), + ]) + ) + ); +} + +#[test] +fn complete_local() { + let mut deps = mock_dependencies(&[]); + deps.querier.add_custom_query_response(|_| { + to_json_binary(&MinIbcFeeResponse { + min_fee: get_standard_fees(), + }) + .unwrap() + }); + base_init(deps.as_mut()); + BONDS + .save( + deps.as_mut().storage, + 1, + &drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: Some(coin(1000, "ld_denom")), + return_type: drop_staking_base::state::mirror::ReturnType::Local, + state: drop_staking_base::state::mirror::BondState::Bonded, + }, + ) + .unwrap(); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("owner", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::Complete { items: vec![1] }, + ) + .unwrap(); + let bond = BONDS.load(&deps.storage, 1); + assert!(bond.is_err()); + assert_eq!( + response, + cosmwasm_std::Response::new() + .add_submessage(cosmwasm_std::SubMsg::new(CosmosMsg::Bank( + cosmwasm_std::BankMsg::Send { + to_address: "backup".to_string(), + amount: vec![coin(1000, "ld_denom")], + } + ))) + .add_event( + cosmwasm_std::Event::new( + "crates.io:drop-staking__drop-mirror-complete".to_string() + ) + .add_attributes(vec![ + attr("action", "complete"), + attr("id", "1"), + attr("return_type", "Bonded"), + attr("coin", "1000ld_denom"), + ]) + ) + ); +} + +#[test] +fn change_return_type() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + BONDS + .save( + deps.as_mut().storage, + 1, + &drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: Some(coin(1000, "ld_denom")), + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Bonded, + }, + ) + .unwrap(); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("owner", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::ChangeReturnType { + id: 1, + return_type: drop_staking_base::state::mirror::ReturnType::Local, + }, + ); + assert_eq!( + response, + Err(drop_staking_base::error::mirror::ContractError::Unauthorized {}) + ); + + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("backup", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::ChangeReturnType { + id: 1, + return_type: drop_staking_base::state::mirror::ReturnType::Local, + }, + ) + .unwrap(); + + let bond = BONDS.load(&deps.storage, 1).unwrap(); + assert_eq!( + bond, + drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: Some(coin(1000, "ld_denom")), + return_type: drop_staking_base::state::mirror::ReturnType::Local, + state: drop_staking_base::state::mirror::BondState::Bonded, + } + ); + assert_eq!( + response, + cosmwasm_std::Response::new().add_event( + cosmwasm_std::Event::new( + "crates.io:drop-staking__drop-mirror-change_return_type".to_string() + ) + .add_attributes(vec![ + attr("action", "change_return_type"), + attr("id", "1"), + attr("return_type", "Local"), + ]) + ) + ); +} + +#[test] +fn update_bond() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + BONDS + .save( + deps.as_mut().storage, + 1, + &drop_staking_base::state::mirror::BondItem { + receiver: "receiver".to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Initiated, + }, + ) + .unwrap(); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("sender", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::UpdateBond { + id: 1, + receiver: "new_receiver".to_string(), + backup: Some("new_backup".to_string()), + return_type: drop_staking_base::state::mirror::ReturnType::Local, + }, + ); + assert_eq!( + response, + Err( + drop_staking_base::error::mirror::ContractError::OwnershipError( + cw_ownable::OwnershipError::NotOwner + ) + ) + ); + + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("owner", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::UpdateBond { + id: 1, + receiver: "new_receiver".to_string(), + backup: Some("new_backup".to_string()), + return_type: drop_staking_base::state::mirror::ReturnType::Local, + }, + ) + .unwrap(); + + let bond = BONDS.load(&deps.storage, 1).unwrap(); + assert_eq!( + bond, + drop_staking_base::state::mirror::BondItem { + receiver: "new_receiver".to_string(), + backup: Some(Addr::unchecked("new_backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Local, + state: drop_staking_base::state::mirror::BondState::Initiated, + } + ); + assert_eq!( + response, + cosmwasm_std::Response::new().add_event( + cosmwasm_std::Event::new( + "crates.io:drop-staking__drop-mirror-update_bond_state".to_string() + ) + .add_attributes(vec![ + attr("action", "update_bond"), + attr("id", "1"), + attr("receiver", "new_receiver"), + attr("backup", "new_backup"), + attr("return_type", "Local"), + ]) + ) + ); +} + +#[test] +fn query_one() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + BONDS + .save( + deps.as_mut().storage, + 1, + &drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Initiated, + }, + ) + .unwrap(); + let one = crate::contract::query( + deps.as_ref(), + mock_env(), + drop_staking_base::msg::mirror::QueryMsg::One { id: 1 }, + ) + .unwrap(); + assert_eq!( + one, + to_json_binary(&drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Initiated, + }) + .unwrap() + ); +} + +#[test] +fn query_all() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + BONDS + .save( + deps.as_mut().storage, + 1, + &drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Initiated, + }, + ) + .unwrap(); + let all = crate::contract::query( + deps.as_ref(), + mock_env(), + drop_staking_base::msg::mirror::QueryMsg::All { + limit: None, + start_after: None, + }, + ) + .unwrap(); + assert_eq!( + all, + to_json_binary(&vec![( + 1, + drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Initiated, + } + )]) + .unwrap() + ); +} + +fn get_standard_fees() -> IbcFee { + IbcFee { + recv_fee: vec![], + ack_fee: cosmwasm_std::coins(100, "untrn"), + timeout_fee: cosmwasm_std::coins(200, "untrn"), + } +} diff --git a/contracts/icq-router/.cargo/config b/contracts/icq-router/.cargo/config new file mode 100644 index 00000000..5d2a9bf7 --- /dev/null +++ b/contracts/icq-router/.cargo/config @@ -0,0 +1,2 @@ +[alias] +schema = "run --bin drop-mirror-schema" diff --git a/contracts/icq-router/Cargo.toml b/contracts/icq-router/Cargo.toml new file mode 100644 index 00000000..e47d0c8d --- /dev/null +++ b/contracts/icq-router/Cargo.toml @@ -0,0 +1,36 @@ +[package] +authors = ["Sergey Ratiashvili "] +description = "Contract to route ICQ features into proper adapter" +edition = "2021" +name = "drop-icq-router" +version = "1.0.0" + +exclude = [ + # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. + "contract.wasm", + "hash.txt", +] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +# for more explicit tests, cargo test --features=backtraces +backtraces = ["cosmwasm-std/backtraces"] +# use library feature to disable all instantiate/execute/query exports +library = [] + +[dependencies] +cosmwasm-schema = { workspace = true } +cosmwasm-std = { workspace = true } +cw-ownable = { workspace = true } +cw2 = { workspace = true } +neutron-sdk = { workspace = true } +drop-staking-base = { workspace = true } +drop-helpers = { workspace = true } +semver = { workspace = true } +cw-storage-plus = { workspace = true } +cw-utils = { workspace = true } +bech32 = { workspace = true } diff --git a/contracts/icq-router/README.md b/contracts/icq-router/README.md new file mode 100644 index 00000000..29381110 --- /dev/null +++ b/contracts/icq-router/README.md @@ -0,0 +1 @@ +# DROP Mirror contract \ No newline at end of file diff --git a/contracts/icq-router/src/bin/drop-icq-router-schema.rs b/contracts/icq-router/src/bin/drop-icq-router-schema.rs new file mode 100644 index 00000000..0667282c --- /dev/null +++ b/contracts/icq-router/src/bin/drop-icq-router-schema.rs @@ -0,0 +1,10 @@ +use cosmwasm_schema::write_api; +use drop_staking_base::msg::icq_router::{ExecuteMsg, InstantiateMsg, QueryMsg}; + +fn main() { + write_api! { + instantiate: InstantiateMsg, + query: QueryMsg, + execute: ExecuteMsg + } +} diff --git a/contracts/icq-router/src/contract.rs b/contracts/icq-router/src/contract.rs new file mode 100644 index 00000000..72a8d89d --- /dev/null +++ b/contracts/icq-router/src/contract.rs @@ -0,0 +1,173 @@ +use cosmwasm_std::{ + attr, ensure, ensure_eq, from_json, to_json_binary, BankMsg, Binary, Coin, CosmosMsg, Deps, + DepsMut, Env, MessageInfo, Response, WasmMsg, +}; +use drop_helpers::answer::response; +use drop_staking_base::msg::icq_router::{BalancesData, DelegationsData}; +use drop_staking_base::state::icq_router::{ + Config, ConfigOptional, BALANCES, CONFIG, DELEGATIONS, NON_NATIVE_REWARD_BALANCES, +}; +use drop_staking_base::{ + error::icq_router::{ContractError, ContractResult}, + msg::icq_router::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}, +}; +use neutron_sdk::bindings::{msg::NeutronMsg, query::NeutronQuery}; + +use std::{env, vec}; + +const CONTRACT_NAME: &str = concat!("crates.io:drop-staking__", env!("CARGO_PKG_NAME")); +const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] +pub fn instantiate( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: InstantiateMsg, +) -> ContractResult> { + let owner = msg.owner.unwrap_or(info.sender.to_string()); + cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + cw_ownable::initialize_owner(deps.storage, deps.api, Some(owner.as_str()))?; + let adapter = deps.api.addr_validate(&msg.adapter)?; + let attrs = vec![ + attr("action", "instantiate"), + attr("adapter", adapter.to_string()), + attr("owner", owner), + ]; + CONFIG.save(deps.storage, &Config { adapter })?; + Ok(response("instantiate", CONTRACT_NAME, attrs)) +} + +#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] +pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> ContractResult { + match msg { + QueryMsg::Balances {} => query_balance(deps), + QueryMsg::Delegations {} => query_delegations(deps), + QueryMsg::NonNativeRewardsBalances {} => query_non_native_rewards_balances(deps), + QueryMsg::Ownership {} => Ok(to_json_binary(&cw_ownable::get_ownership(deps.storage)?)?), + QueryMsg::Config {} => Ok(to_json_binary(&CONFIG.load(deps.storage)?)?), + } +} + +#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] +pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> ContractResult> { + match msg { + ExecuteMsg::UpdateValidators { validators } => { + update_validators(deps, info, env, validators) + } + ExecuteMsg::UpdateConfig { new_config } => update_config(deps, info, new_config), + ExecuteMsg::UpdateOwnership(action) => { + let attrs = vec![attr("action", "update_ownership")]; + cw_ownable::update_ownership(deps.into_empty(), &env.block, &info.sender, action)?; + Ok(response("update_ownership", CONTRACT_NAME, attrs)) + } + ExecuteMsg::UpdateBalances { balances } => update_balances(deps, info, env, balances), + ExecuteMsg::UpdateDelegations { delegations } => { + update_delegations(deps, info, env, delegations) + } + } +} + +#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] +pub fn migrate( + deps: DepsMut, + _env: Env, + _msg: MigrateMsg, +) -> ContractResult> { + let version: semver::Version = CONTRACT_VERSION.parse()?; + let storage_version: semver::Version = + cw2::get_contract_version(deps.storage)?.version.parse()?; + if storage_version < version { + cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + } + Ok(Response::new()) +} + +fn query_balance(deps: Deps) -> ContractResult { + let balance = BALANCES.load(deps.storage)?; + Ok(to_json_binary(&balance)?) +} + +fn query_delegations(deps: Deps) -> ContractResult { + let delegations = DELEGATIONS.load(deps.storage)?; + Ok(to_json_binary(&delegations)?) +} + +fn query_non_native_rewards_balances(deps: Deps) -> ContractResult { + let balances = NON_NATIVE_REWARD_BALANCES.load(deps.storage)?; + Ok(to_json_binary(&balances)?) +} + +fn update_balances( + deps: DepsMut, + info: MessageInfo, + _env: Env, + balances: BalancesData, +) -> ContractResult> { + let config = CONFIG.load(deps.storage)?; + ensure_eq!(info.sender, config.adapter, ContractError::Unauthorized {}); + let old_data = BALANCES.load(deps.storage)?; + ensure!( + balances.remote_height > old_data.remote_height, + ContractError::OutdatedData + ); + BALANCES.save(deps.storage, &balances)?; + Ok(Response::new()) +} + +fn update_config( + deps: DepsMut, + info: MessageInfo, + new_config: ConfigOptional, +) -> ContractResult> { + cw_ownable::assert_owner(deps.storage, &info.sender)?; + let mut config = CONFIG.load(deps.storage)?; + if let Some(adapter) = new_config.adapter { + config.adapter = deps.api.addr_validate(&adapter)?; + } + CONFIG.save(deps.storage, &config)?; + Ok(Response::new()) +} + +fn update_delegations( + deps: DepsMut, + info: MessageInfo, + _env: Env, + delegations: DelegationsData, +) -> ContractResult> { + let config = CONFIG.load(deps.storage)?; + ensure_eq!(info.sender, config.adapter, ContractError::Unauthorized {}); + let old_data = DELEGATIONS.load(deps.storage)?; + ensure!( + delegations.remote_height > old_data.remote_height, + ContractError::OutdatedData + ); + DELEGATIONS.save(deps.storage, &delegations)?; + Ok(Response::new()) +} + +fn update_validators( + deps: DepsMut, + _info: MessageInfo, + _env: Env, + validators: Vec, +) -> ContractResult> { + let config = CONFIG.load(deps.storage)?; + let res = response( + "update_validators", + CONTRACT_NAME, + [attr("validators", format!("{:?}", validators))], + ); + Ok(res.add_message(CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: config.adapter.to_string(), + msg: to_json_binary( + &drop_staking_base::msg::icq_adapter::ExecuteMsg::UpdateValidatorSet { validators }, + )?, + funds: vec![], + }))) +} diff --git a/contracts/icq-router/src/lib.rs b/contracts/icq-router/src/lib.rs new file mode 100644 index 00000000..c231df08 --- /dev/null +++ b/contracts/icq-router/src/lib.rs @@ -0,0 +1,4 @@ +pub mod contract; + +// #[cfg(test)] +// mod tests; diff --git a/contracts/icq-router/src/tests.rs b/contracts/icq-router/src/tests.rs new file mode 100644 index 00000000..c6bc0a41 --- /dev/null +++ b/contracts/icq-router/src/tests.rs @@ -0,0 +1,645 @@ +use cosmwasm_std::{ + attr, coin, + testing::{mock_env, mock_info}, + to_json_binary, Addr, CosmosMsg, CustomQuery, DepsMut, Uint128, WasmMsg, +}; +use drop_helpers::testing::mock_dependencies; +use drop_staking_base::state::mirror::{BONDS, CONFIG, COUNTER}; +use neutron_sdk::{ + bindings::msg::{IbcFee, NeutronMsg}, + query::min_ibc_fee::MinIbcFeeResponse, + sudo::msg::RequestPacketTimeoutHeight, +}; + +fn base_init(deps: DepsMut) +where + T: CustomQuery, +{ + let config = drop_staking_base::state::mirror::Config { + core_contract: "core".to_string(), + source_port: "source_port".to_string(), + source_channel: "source_channel".to_string(), + ibc_timeout: 10, + prefix: "prefix".to_string(), + }; + CONFIG.save(deps.storage, &config).unwrap(); + COUNTER.save(deps.storage, &0).unwrap(); + cw_ownable::initialize_owner(deps.storage, deps.api, Some("owner")).unwrap(); +} + +#[test] +fn test_instantiate() { + let mut deps = mock_dependencies(&[]); + let response = crate::contract::instantiate( + deps.as_mut(), + mock_env(), + mock_info("sender", &[]), + drop_staking_base::msg::mirror::InstantiateMsg { + core_contract: "core".to_string(), + source_port: "source_port".to_string(), + source_channel: "source_channel".to_string(), + ibc_timeout: 10, + owner: Some("owner".to_string()), + prefix: "prefix".to_string(), + }, + ) + .unwrap(); + assert_eq!( + response, + cosmwasm_std::Response::new().add_event( + cosmwasm_std::Event::new("crates.io:drop-staking__drop-mirror-instantiate".to_string()) + .add_attributes(vec![attr("action", "instantiate"), attr("owner", "owner")]) + ) + ); + let config = CONFIG.load(&deps.storage).unwrap(); + assert_eq!( + config, + drop_staking_base::state::mirror::Config { + core_contract: "core".to_string(), + source_port: "source_port".to_string(), + source_channel: "source_channel".to_string(), + ibc_timeout: 10, + prefix: "prefix".to_string(), + } + ); + let owner = cw_ownable::get_ownership(&deps.storage).unwrap(); + assert_eq!(owner.owner, Some(Addr::unchecked("owner"))); + let counter = COUNTER.load(&deps.storage).unwrap(); + assert_eq!(counter, 0); +} + +#[test] +fn test_instantiate_wo_owner() { + let mut deps = mock_dependencies(&[]); + let response = crate::contract::instantiate( + deps.as_mut(), + mock_env(), + mock_info("sender", &[]), + drop_staking_base::msg::mirror::InstantiateMsg { + core_contract: "core".to_string(), + source_port: "source_port".to_string(), + source_channel: "source_channel".to_string(), + ibc_timeout: 10, + owner: None, + prefix: "prefix".to_string(), + }, + ) + .unwrap(); + assert_eq!( + response, + cosmwasm_std::Response::new().add_event( + cosmwasm_std::Event::new("crates.io:drop-staking__drop-mirror-instantiate".to_string()) + .add_attributes(vec![attr("action", "instantiate"), attr("owner", "sender")]) + ) + ); + let config = CONFIG.load(&deps.storage).unwrap(); + assert_eq!( + config, + drop_staking_base::state::mirror::Config { + core_contract: "core".to_string(), + source_port: "source_port".to_string(), + source_channel: "source_channel".to_string(), + ibc_timeout: 10, + prefix: "prefix".to_string(), + } + ); + let owner = cw_ownable::get_ownership(&deps.storage).unwrap(); + assert_eq!(owner.owner, Some(Addr::unchecked("sender"))); +} + +#[test] +fn update_config() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("owner", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::UpdateConfig { + new_config: drop_staking_base::state::mirror::ConfigOptional { + core_contract: Some("new_core".to_string()), + source_port: Some("new_source_port".to_string()), + source_channel: Some("new_source_channel".to_string()), + ibc_timeout: Some(20), + prefix: Some("new_prefix".to_string()), + }, + }, + ) + .unwrap(); + assert_eq!( + response, + cosmwasm_std::Response::new().add_event( + cosmwasm_std::Event::new( + "crates.io:drop-staking__drop-mirror-update_config".to_string() + ) + .add_attributes(vec![ + attr("action", "update_config"), + attr("core_contract", "new_core"), + attr("source_port", "new_source_port"), + attr("source_channel", "new_source_channel"), + attr("ibc_timeout", "20"), + attr("prefix", "new_prefix"), + ]) + ) + ); + let config = CONFIG.load(&deps.storage).unwrap(); + assert_eq!( + config, + drop_staking_base::state::mirror::Config { + core_contract: "new_core".to_string(), + source_port: "new_source_port".to_string(), + source_channel: "new_source_channel".to_string(), + ibc_timeout: 20, + prefix: "new_prefix".to_string(), + } + ); +} + +#[test] +fn bond_wrong_receiver() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("sender", &[coin(1000, "mytoken")]), + drop_staking_base::msg::mirror::ExecuteMsg::Bond { + receiver: "some".to_string(), + r#ref: Some("reff".to_string()), + backup: Some("backup".to_string()), + }, + ); + assert_eq!( + response, + Err(drop_staking_base::error::mirror::ContractError::InvalidPrefix {}) + ); +} + +#[test] +fn bond_no_funds() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("sender", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::Bond { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + r#ref: Some("reff".to_string()), + backup: Some("backup".to_string()), + }, + ); + assert_eq!( + response, + Err( + drop_staking_base::error::mirror::ContractError::PaymentError( + cw_utils::PaymentError::NoFunds {} + ) + ) + ); +} + +#[test] +fn bond() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("sender", &[coin(1000, "mytoken")]), + drop_staking_base::msg::mirror::ExecuteMsg::Bond { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + r#ref: Some("reff".to_string()), + backup: Some("backup".to_string()), + }, + ) + .unwrap(); + let counter = COUNTER.load(&deps.storage).unwrap(); + assert_eq!(counter, 1); + let bond = BONDS.load(&deps.storage, 1).unwrap(); + assert_eq!( + bond, + drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Initiated, + } + ); + assert_eq!( + response, + cosmwasm_std::Response::new() + .add_submessage(cosmwasm_std::SubMsg::reply_on_success( + WasmMsg::Execute { + contract_addr: "core".to_string(), + msg: to_json_binary(&drop_staking_base::msg::core::ExecuteMsg::Bond { + receiver: None, + r#ref: Some("reff".to_string()) + }) + .unwrap(), + funds: vec![coin(1000, "mytoken")], + }, + 1 + )) + .add_event( + cosmwasm_std::Event::new("crates.io:drop-staking__drop-mirror-bond".to_string()) + .add_attributes(vec![ + attr("action", "bond"), + attr("id", "1"), + attr( + "receiver", + "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + ), + attr("ref", "reff"), + attr("backup", "backup"), + ]) + ) + ); +} + +#[test] +fn complete_remote() { + let mut deps = mock_dependencies(&[]); + deps.querier.add_custom_query_response(|_| { + to_json_binary(&MinIbcFeeResponse { + min_fee: get_standard_fees(), + }) + .unwrap() + }); + base_init(deps.as_mut()); + BONDS + .save( + deps.as_mut().storage, + 1, + &drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: Some(coin(1000, "ld_denom")), + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Bonded, + }, + ) + .unwrap(); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("owner", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::Complete { items: vec![1] }, + ) + .unwrap(); + let bond = BONDS.load(&deps.storage, 1).unwrap(); + assert_eq!( + bond, + drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: Some(coin(1000, "ld_denom")), + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Sent, + } + ); + assert_eq!( + response, + cosmwasm_std::Response::new() + .add_submessage(cosmwasm_std::SubMsg::new(CosmosMsg::Custom( + NeutronMsg::IbcTransfer { + source_port: "source_port".to_string(), + source_channel: "source_channel".to_string(), + token: coin(1000, "ld_denom"), + sender: "cosmos2contract".to_string(), + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + timeout_height: RequestPacketTimeoutHeight { + revision_number: None, + revision_height: None + }, + timeout_timestamp: 1571797429879305533, + memo: "1".to_string(), + fee: get_standard_fees(), + } + ))) + .add_event( + cosmwasm_std::Event::new( + "crates.io:drop-staking__drop-mirror-complete".to_string() + ) + .add_attributes(vec![ + attr("action", "complete"), + attr("id", "1"), + attr("return_type", "Bonded"), + attr("coin", "1000ld_denom"), + ]) + ) + ); +} + +#[test] +fn complete_local() { + let mut deps = mock_dependencies(&[]); + deps.querier.add_custom_query_response(|_| { + to_json_binary(&MinIbcFeeResponse { + min_fee: get_standard_fees(), + }) + .unwrap() + }); + base_init(deps.as_mut()); + BONDS + .save( + deps.as_mut().storage, + 1, + &drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: Some(coin(1000, "ld_denom")), + return_type: drop_staking_base::state::mirror::ReturnType::Local, + state: drop_staking_base::state::mirror::BondState::Bonded, + }, + ) + .unwrap(); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("owner", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::Complete { items: vec![1] }, + ) + .unwrap(); + let bond = BONDS.load(&deps.storage, 1); + assert!(bond.is_err()); + assert_eq!( + response, + cosmwasm_std::Response::new() + .add_submessage(cosmwasm_std::SubMsg::new(CosmosMsg::Bank( + cosmwasm_std::BankMsg::Send { + to_address: "backup".to_string(), + amount: vec![coin(1000, "ld_denom")], + } + ))) + .add_event( + cosmwasm_std::Event::new( + "crates.io:drop-staking__drop-mirror-complete".to_string() + ) + .add_attributes(vec![ + attr("action", "complete"), + attr("id", "1"), + attr("return_type", "Bonded"), + attr("coin", "1000ld_denom"), + ]) + ) + ); +} + +#[test] +fn change_return_type() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + BONDS + .save( + deps.as_mut().storage, + 1, + &drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: Some(coin(1000, "ld_denom")), + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Bonded, + }, + ) + .unwrap(); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("owner", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::ChangeReturnType { + id: 1, + return_type: drop_staking_base::state::mirror::ReturnType::Local, + }, + ); + assert_eq!( + response, + Err(drop_staking_base::error::mirror::ContractError::Unauthorized {}) + ); + + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("backup", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::ChangeReturnType { + id: 1, + return_type: drop_staking_base::state::mirror::ReturnType::Local, + }, + ) + .unwrap(); + + let bond = BONDS.load(&deps.storage, 1).unwrap(); + assert_eq!( + bond, + drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: Some(coin(1000, "ld_denom")), + return_type: drop_staking_base::state::mirror::ReturnType::Local, + state: drop_staking_base::state::mirror::BondState::Bonded, + } + ); + assert_eq!( + response, + cosmwasm_std::Response::new().add_event( + cosmwasm_std::Event::new( + "crates.io:drop-staking__drop-mirror-change_return_type".to_string() + ) + .add_attributes(vec![ + attr("action", "change_return_type"), + attr("id", "1"), + attr("return_type", "Local"), + ]) + ) + ); +} + +#[test] +fn update_bond() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + BONDS + .save( + deps.as_mut().storage, + 1, + &drop_staking_base::state::mirror::BondItem { + receiver: "receiver".to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Initiated, + }, + ) + .unwrap(); + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("sender", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::UpdateBond { + id: 1, + receiver: "new_receiver".to_string(), + backup: Some("new_backup".to_string()), + return_type: drop_staking_base::state::mirror::ReturnType::Local, + }, + ); + assert_eq!( + response, + Err( + drop_staking_base::error::mirror::ContractError::OwnershipError( + cw_ownable::OwnershipError::NotOwner + ) + ) + ); + + let response = crate::contract::execute( + deps.as_mut(), + mock_env(), + mock_info("owner", &[]), + drop_staking_base::msg::mirror::ExecuteMsg::UpdateBond { + id: 1, + receiver: "new_receiver".to_string(), + backup: Some("new_backup".to_string()), + return_type: drop_staking_base::state::mirror::ReturnType::Local, + }, + ) + .unwrap(); + + let bond = BONDS.load(&deps.storage, 1).unwrap(); + assert_eq!( + bond, + drop_staking_base::state::mirror::BondItem { + receiver: "new_receiver".to_string(), + backup: Some(Addr::unchecked("new_backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Local, + state: drop_staking_base::state::mirror::BondState::Initiated, + } + ); + assert_eq!( + response, + cosmwasm_std::Response::new().add_event( + cosmwasm_std::Event::new( + "crates.io:drop-staking__drop-mirror-update_bond_state".to_string() + ) + .add_attributes(vec![ + attr("action", "update_bond"), + attr("id", "1"), + attr("receiver", "new_receiver"), + attr("backup", "new_backup"), + attr("return_type", "Local"), + ]) + ) + ); +} + +#[test] +fn query_one() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + BONDS + .save( + deps.as_mut().storage, + 1, + &drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Initiated, + }, + ) + .unwrap(); + let one = crate::contract::query( + deps.as_ref(), + mock_env(), + drop_staking_base::msg::mirror::QueryMsg::One { id: 1 }, + ) + .unwrap(); + assert_eq!( + one, + to_json_binary(&drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Initiated, + }) + .unwrap() + ); +} + +#[test] +fn query_all() { + let mut deps = mock_dependencies(&[]); + base_init(deps.as_mut()); + BONDS + .save( + deps.as_mut().storage, + 1, + &drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Initiated, + }, + ) + .unwrap(); + let all = crate::contract::query( + deps.as_ref(), + mock_env(), + drop_staking_base::msg::mirror::QueryMsg::All { + limit: None, + start_after: None, + }, + ) + .unwrap(); + assert_eq!( + all, + to_json_binary(&vec![( + 1, + drop_staking_base::state::mirror::BondItem { + receiver: "prefix10yaps46wgmzrsslmeqpc9wxpssu7zuw4rrfv8d5rv8pudt8m88446jgnu2j" + .to_string(), + backup: Some(Addr::unchecked("backup".to_string())), + amount: Uint128::new(1000), + received: None, + return_type: drop_staking_base::state::mirror::ReturnType::Remote, + state: drop_staking_base::state::mirror::BondState::Initiated, + } + )]) + .unwrap() + ); +} + +fn get_standard_fees() -> IbcFee { + IbcFee { + recv_fee: vec![], + ack_fee: cosmwasm_std::coins(100, "untrn"), + timeout_fee: cosmwasm_std::coins(200, "untrn"), + } +} diff --git a/contracts/puppeteer-authz/src/msg.rs b/contracts/puppeteer-authz/src/msg.rs index ce4e4394..21c48409 100644 --- a/contracts/puppeteer-authz/src/msg.rs +++ b/contracts/puppeteer-authz/src/msg.rs @@ -56,7 +56,6 @@ impl ExecuteMsg { pub fn to_base_enum(&self) -> BaseExecuteMsg { match self { ExecuteMsg::RegisterICA {} => BaseExecuteMsg::RegisterICA {}, - ExecuteMsg::RegisterQuery {} => BaseExecuteMsg::RegisterQuery {}, ExecuteMsg::SetFees { recv_fee, ack_fee, diff --git a/packages/base/src/error/icq_adapter.rs b/packages/base/src/error/icq_adapter.rs new file mode 100644 index 00000000..235eaeac --- /dev/null +++ b/packages/base/src/error/icq_adapter.rs @@ -0,0 +1,26 @@ +use cosmwasm_std::StdError; +use cw_ownable::OwnershipError; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + #[error("{0}")] + OwnershipError(#[from] OwnershipError), + + #[error("Semver parsing error: {0}")] + SemVer(String), + + #[error("Unauthorized")] + Unauthorized, +} + +impl From for ContractError { + fn from(err: semver::Error) -> Self { + Self::SemVer(err.to_string()) + } +} + +pub type ContractResult = Result; diff --git a/packages/base/src/error/icq_router.rs b/packages/base/src/error/icq_router.rs new file mode 100644 index 00000000..b4632e3b --- /dev/null +++ b/packages/base/src/error/icq_router.rs @@ -0,0 +1,29 @@ +use cosmwasm_std::StdError; +use cw_ownable::OwnershipError; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + #[error("{0}")] + OwnershipError(#[from] OwnershipError), + + #[error("Semver parsing error: {0}")] + SemVer(String), + + #[error("Unauthorized")] + Unauthorized, + + #[error("Outdated data")] + OutdatedData, +} + +impl From for ContractError { + fn from(err: semver::Error) -> Self { + Self::SemVer(err.to_string()) + } +} + +pub type ContractResult = Result; diff --git a/packages/base/src/error/mod.rs b/packages/base/src/error/mod.rs index 7abfee6a..483d8fbb 100644 --- a/packages/base/src/error/mod.rs +++ b/packages/base/src/error/mod.rs @@ -2,6 +2,8 @@ pub mod astroport_exchange_handler; pub mod core; pub mod distribution; pub mod factory; +pub mod icq_adapter; +pub mod icq_router; pub mod lsm_share_bond_provider; pub mod mirror; pub mod native_bond_provider; diff --git a/packages/base/src/msg/icq_adapter.rs b/packages/base/src/msg/icq_adapter.rs new file mode 100644 index 00000000..d166bd1a --- /dev/null +++ b/packages/base/src/msg/icq_adapter.rs @@ -0,0 +1,29 @@ +use cosmwasm_schema::cw_serde; + +#[cw_ownable::cw_ownable_query] +#[cw_serde] +#[derive(cosmwasm_schema::QueryResponses)] +pub enum QueryMsg { + #[returns(crate::state::icq_router::Config)] + Config {}, + #[returns(E)] + Extention(E), +} + +#[cw_serde] +pub enum ExecuteMsg { + UpdateValidatorSet { validators: Vec }, + UpdateBalances {}, + UpdateDelegations {}, + UpdateConfig {}, +} + +#[cw_serde] +pub struct InstantiateMsg { + pub router: String, + pub owner: Option, + pub opts: O, +} + +#[cw_serde] +pub struct MigrateMsg {} diff --git a/packages/base/src/msg/icq_router.rs b/packages/base/src/msg/icq_router.rs new file mode 100644 index 00000000..1d5d801d --- /dev/null +++ b/packages/base/src/msg/icq_router.rs @@ -0,0 +1,72 @@ +use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::{Addr, Decimal256, Timestamp}; +use neutron_sdk::interchain_queries::v047::types::Balances; + +use crate::state::icq_router::ConfigOptional; + +#[cw_ownable::cw_ownable_query] +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg { + #[returns(crate::state::icq_router::Config)] + Config {}, + #[returns(DelegationsData)] + Delegations {}, + #[returns(BalancesData)] + Balances {}, + #[returns(BalancesData)] + NonNativeRewardsBalances {}, +} + +#[cw_ownable::cw_ownable_execute] +#[cw_serde] +pub enum ExecuteMsg { + UpdateValidators { validators: Vec }, + UpdateConfig { new_config: ConfigOptional }, + UpdateBalances { balances: BalancesData }, + UpdateDelegations { delegations: DelegationsData }, +} + +#[cw_serde] +pub struct InstantiateMsg { + pub adapter: String, + pub owner: Option, +} + +#[cw_serde] +pub struct MigrateMsg {} + +pub type RemoteHeight = u64; +pub type LocalHeight = u64; + +#[cw_serde] +pub struct DelegationsData { + pub delegations: Delegations, + pub remote_height: u64, + pub local_height: u64, + pub timestamp: Timestamp, +} + +#[cw_serde] +pub struct BalancesData { + pub balances: Balances, + pub remote_height: u64, + pub local_height: u64, + pub timestamp: Timestamp, +} + +#[cw_serde] +pub struct Delegations { + pub delegations: Vec, +} + +#[cw_serde] +pub struct DropDelegation { + pub delegator: Addr, + /// A validator address (e.g. cosmosvaloper1...) + pub validator: String, + /// How much we have locked in the delegation + pub amount: cosmwasm_std::Coin, + /// How many shares the delegator has in the validator + pub share_ratio: Decimal256, +} diff --git a/packages/base/src/msg/mod.rs b/packages/base/src/msg/mod.rs index 7eca191e..2a5c9bd0 100644 --- a/packages/base/src/msg/mod.rs +++ b/packages/base/src/msg/mod.rs @@ -4,6 +4,8 @@ pub mod core; pub mod distribution; pub mod factory; pub mod hook_tester; +pub mod icq_adapter; +pub mod icq_router; pub mod lsm_share_bond_provider; pub mod mirror; pub mod native_bond_provider; @@ -17,7 +19,6 @@ pub mod reward_handler; pub mod rewards_manager; pub mod splitter; pub mod strategy; - #[cfg(test)] mod tests; pub mod token; diff --git a/packages/base/src/msg/puppeteer.rs b/packages/base/src/msg/puppeteer.rs index 15fd6336..0b8a6bed 100644 --- a/packages/base/src/msg/puppeteer.rs +++ b/packages/base/src/msg/puppeteer.rs @@ -92,7 +92,6 @@ impl ExecuteMsg { pub fn to_base_enum(&self) -> BaseExecuteMsg { match self { ExecuteMsg::RegisterICA {} => BaseExecuteMsg::RegisterICA {}, - ExecuteMsg::RegisterQuery {} => BaseExecuteMsg::RegisterQuery {}, _ => unimplemented!(), } } diff --git a/packages/base/src/state/icq_adapter.rs b/packages/base/src/state/icq_adapter.rs new file mode 100644 index 00000000..7808db12 --- /dev/null +++ b/packages/base/src/state/icq_adapter.rs @@ -0,0 +1,21 @@ +use cosmwasm_schema::cw_serde; +use cosmwasm_std::Addr; +use cw_storage_plus::Item; + +use crate::msg::icq_router::{BalancesData, DelegationsData}; + +#[cw_serde] +pub struct Config { + pub router: Addr, + pub options: E, +} + +#[cw_serde] +pub struct ConfigOptional { + pub router: Option, +} + +pub const CONFIG: Item = Item::new("config"); +pub const BALANCES: Item = Item::new("balances"); +pub const DELEGATIONS: Item = Item::new("delegations"); +pub const NON_NATIVE_REWARD_BALANCES: Item = Item::new("non_native_reward_balances"); diff --git a/packages/base/src/state/icq_router.rs b/packages/base/src/state/icq_router.rs new file mode 100644 index 00000000..a9de9bb2 --- /dev/null +++ b/packages/base/src/state/icq_router.rs @@ -0,0 +1,20 @@ +use cosmwasm_schema::cw_serde; +use cosmwasm_std::Addr; +use cw_storage_plus::Item; + +use crate::msg::icq_router::{BalancesData, DelegationsData}; + +#[cw_serde] +pub struct Config { + pub adapter: Addr, +} + +#[cw_serde] +pub struct ConfigOptional { + pub adapter: Option, +} + +pub const CONFIG: Item = Item::new("config"); +pub const BALANCES: Item = Item::new("balances"); +pub const DELEGATIONS: Item = Item::new("delegations"); +pub const NON_NATIVE_REWARD_BALANCES: Item = Item::new("non_native_reward_balances"); diff --git a/packages/base/src/state/mod.rs b/packages/base/src/state/mod.rs index 057f7a99..2a55e728 100644 --- a/packages/base/src/state/mod.rs +++ b/packages/base/src/state/mod.rs @@ -3,6 +3,8 @@ pub mod bond_providers; pub mod core; pub mod factory; pub mod hook_tester; +pub mod icq_adapter; +pub mod icq_router; pub mod lsm_share_bond_provider; pub mod mirror; pub mod native_bond_provider; diff --git a/packages/puppeteer-base/src/execute.rs b/packages/puppeteer-base/src/execute.rs index b6bb2064..9e809721 100644 --- a/packages/puppeteer-base/src/execute.rs +++ b/packages/puppeteer-base/src/execute.rs @@ -12,7 +12,6 @@ use cosmwasm_std::{ use drop_helpers::answer::response; use neutron_sdk::{ bindings::{msg::NeutronMsg, query::NeutronQuery}, - interchain_queries::v045::new_register_transfers_query_msg, NeutronError, NeutronResult, }; use serde::{de::DeserializeOwned, Serialize}; @@ -44,7 +43,6 @@ where ) -> ContractResult> { match msg { ExecuteMsg::RegisterICA {} => self.execute_register_ica(deps, info), - ExecuteMsg::RegisterQuery {} => self.register_transfers_query(deps), } } @@ -126,20 +124,4 @@ where .register(deps.storage, config.connection_id(), ICA_ID, register_fee)?; Ok(response("register-ica", "puppeteer-base", attrs).add_message(register_msg)) } - - fn register_transfers_query( - &self, - deps: DepsMut, - ) -> ContractResult> { - let config = self.config.load(deps.storage)?; - let ica = self.ica.get_address(deps.storage)?; - - let msg = new_register_transfers_query_msg( - config.connection_id(), - ica, - config.update_period(), - None, - )?; - Ok(Response::new().add_message(msg)) - } } diff --git a/packages/puppeteer-base/src/msg.rs b/packages/puppeteer-base/src/msg.rs index ef9783b1..b325767a 100644 --- a/packages/puppeteer-base/src/msg.rs +++ b/packages/puppeteer-base/src/msg.rs @@ -5,7 +5,6 @@ use schemars::JsonSchema; #[cw_serde] pub enum ExecuteMsg { RegisterICA {}, - RegisterQuery {}, } #[cw_serde] diff --git a/ts-client/lib/contractLib/dropCore.d.ts b/ts-client/lib/contractLib/dropCore.d.ts index c336ece2..bfcaf909 100644 --- a/ts-client/lib/contractLib/dropCore.d.ts +++ b/ts-client/lib/contractLib/dropCore.d.ts @@ -236,20 +236,15 @@ export interface Config { base_denom: string; bond_limit?: Uint128 | null; emergency_address?: string | null; + factory_contract: Addr; icq_update_delay: number; idle_min_interval: number; pump_ica_address?: string | null; - puppeteer_contract: Addr; remote_denom: string; - strategy_contract: Addr; - token_contract: Addr; transfer_channel_id: string; unbond_batch_switch_time: number; unbonding_period: number; unbonding_safe_period: number; - validators_set_contract: Addr; - withdrawal_manager_contract: Addr; - withdrawal_voucher_contract: Addr; } export interface FailedBatchResponse { response?: number | null; @@ -395,21 +390,15 @@ export interface ConfigOptional { base_denom?: string | null; bond_limit?: Uint128 | null; emergency_address?: string | null; + factory_contract?: string | null; idle_min_interval?: number | null; pump_ica_address?: string | null; - puppeteer_contract?: string | null; remote_denom?: string | null; rewards_receiver?: string | null; - staker_contract?: string | null; - strategy_contract?: string | null; - token_contract?: string | null; transfer_channel_id?: string | null; unbond_batch_switch_time?: number | null; unbonding_period?: number | null; unbonding_safe_period?: number | null; - validators_set_contract?: string | null; - withdrawal_manager_contract?: string | null; - withdrawal_voucher_contract?: string | null; } export interface UpdateWithdrawnAmountArgs { batch_id: number; @@ -434,21 +423,16 @@ export interface InstantiateMsg { base_denom: string; bond_limit?: Uint128 | null; emergency_address?: string | null; + factory_contract: string; icq_update_delay: number; idle_min_interval: number; owner: string; pump_ica_address?: string | null; - puppeteer_contract: string; remote_denom: string; - strategy_contract: string; - token_contract: string; transfer_channel_id: string; unbond_batch_switch_time: number; unbonding_period: number; unbonding_safe_period: number; - validators_set_contract: string; - withdrawal_manager_contract: string; - withdrawal_voucher_contract: string; } export declare class Client { private readonly client; diff --git a/ts-client/lib/contractLib/dropFactory.d.ts b/ts-client/lib/contractLib/dropFactory.d.ts index c19f60c5..258cc4da 100644 --- a/ts-client/lib/contractLib/dropFactory.d.ts +++ b/ts-client/lib/contractLib/dropFactory.d.ts @@ -715,21 +715,15 @@ export interface ConfigOptional { base_denom?: string | null; bond_limit?: Uint128 | null; emergency_address?: string | null; + factory_contract?: string | null; idle_min_interval?: number | null; pump_ica_address?: string | null; - puppeteer_contract?: string | null; remote_denom?: string | null; rewards_receiver?: string | null; - staker_contract?: string | null; - strategy_contract?: string | null; - token_contract?: string | null; transfer_channel_id?: string | null; unbond_batch_switch_time?: number | null; unbonding_period?: number | null; unbonding_safe_period?: number | null; - validators_set_contract?: string | null; - withdrawal_manager_contract?: string | null; - withdrawal_voucher_contract?: string | null; } export interface ConfigOptional2 { provider_proposals_contract?: string | null; diff --git a/ts-client/src/contractLib/dropCore.ts b/ts-client/src/contractLib/dropCore.ts index ee49ea22..2289a4a3 100644 --- a/ts-client/src/contractLib/dropCore.ts +++ b/ts-client/src/contractLib/dropCore.ts @@ -299,20 +299,15 @@ export interface Config { base_denom: string; bond_limit?: Uint128 | null; emergency_address?: string | null; + factory_contract: Addr; icq_update_delay: number; idle_min_interval: number; pump_ica_address?: string | null; - puppeteer_contract: Addr; remote_denom: string; - strategy_contract: Addr; - token_contract: Addr; transfer_channel_id: string; unbond_batch_switch_time: number; unbonding_period: number; unbonding_safe_period: number; - validators_set_contract: Addr; - withdrawal_manager_contract: Addr; - withdrawal_voucher_contract: Addr; } export interface FailedBatchResponse { response?: number | null; @@ -454,21 +449,15 @@ export interface ConfigOptional { base_denom?: string | null; bond_limit?: Uint128 | null; emergency_address?: string | null; + factory_contract?: string | null; idle_min_interval?: number | null; pump_ica_address?: string | null; - puppeteer_contract?: string | null; remote_denom?: string | null; rewards_receiver?: string | null; - staker_contract?: string | null; - strategy_contract?: string | null; - token_contract?: string | null; transfer_channel_id?: string | null; unbond_batch_switch_time?: number | null; unbonding_period?: number | null; unbonding_safe_period?: number | null; - validators_set_contract?: string | null; - withdrawal_manager_contract?: string | null; - withdrawal_voucher_contract?: string | null; } export interface UpdateWithdrawnAmountArgs { batch_id: number; @@ -493,21 +482,16 @@ export interface InstantiateMsg { base_denom: string; bond_limit?: Uint128 | null; emergency_address?: string | null; + factory_contract: string; icq_update_delay: number; idle_min_interval: number; owner: string; pump_ica_address?: string | null; - puppeteer_contract: string; remote_denom: string; - strategy_contract: string; - token_contract: string; transfer_channel_id: string; unbond_batch_switch_time: number; unbonding_period: number; unbonding_safe_period: number; - validators_set_contract: string; - withdrawal_manager_contract: string; - withdrawal_voucher_contract: string; } diff --git a/ts-client/src/contractLib/dropFactory.ts b/ts-client/src/contractLib/dropFactory.ts index 09ae816c..aaa2b12b 100644 --- a/ts-client/src/contractLib/dropFactory.ts +++ b/ts-client/src/contractLib/dropFactory.ts @@ -785,21 +785,15 @@ export interface ConfigOptional { base_denom?: string | null; bond_limit?: Uint128 | null; emergency_address?: string | null; + factory_contract?: string | null; idle_min_interval?: number | null; pump_ica_address?: string | null; - puppeteer_contract?: string | null; remote_denom?: string | null; rewards_receiver?: string | null; - staker_contract?: string | null; - strategy_contract?: string | null; - token_contract?: string | null; transfer_channel_id?: string | null; unbond_batch_switch_time?: number | null; unbonding_period?: number | null; unbonding_safe_period?: number | null; - validators_set_contract?: string | null; - withdrawal_manager_contract?: string | null; - withdrawal_voucher_contract?: string | null; } export interface ConfigOptional2 { provider_proposals_contract?: string | null; From 6a8043d22b0de204c4d0cd59a03806c92a7ecd66 Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Tue, 17 Dec 2024 17:22:15 +0100 Subject: [PATCH 09/14] wip --- contracts/icq-adapter-kv/src/contract.rs | 187 ++++++++++++----------- contracts/icq-adapter-kv/src/lib.rs | 1 + contracts/icq-adapter-kv/src/msg.rs | 7 +- contracts/icq-adapter-kv/src/store.rs | 4 + packages/base/src/error/icq_adapter.rs | 7 + packages/base/src/msg/icq_adapter.rs | 12 +- packages/base/src/state/icq_adapter.rs | 42 ++++- rust-toolchain.toml | 2 +- 8 files changed, 165 insertions(+), 97 deletions(-) create mode 100644 contracts/icq-adapter-kv/src/store.rs diff --git a/contracts/icq-adapter-kv/src/contract.rs b/contracts/icq-adapter-kv/src/contract.rs index 44916ac9..8ce1ac00 100644 --- a/contracts/icq-adapter-kv/src/contract.rs +++ b/contracts/icq-adapter-kv/src/contract.rs @@ -1,10 +1,11 @@ use cosmwasm_std::{ - attr, ensure, ensure_eq, to_json_binary, Binary, CosmosMsg, Deps, DepsMut, Env, MessageInfo, - Response, WasmMsg, + attr, ensure, ensure_eq, to_json_binary, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, + MessageInfo, Order, Reply, Response, StdError, StdResult, SubMsg, WasmMsg, }; use drop_helpers::answer::response; -use drop_staking_base::msg::icq_router::{BalancesData, DelegationsData}; -use drop_staking_base::state::icq_adapter::{Config, ConfigOptional, CONFIG}; +use drop_helpers::icq::new_delegations_and_balance_query_msg; +use drop_helpers::query_id::get_query_id; +use drop_staking_base::state::icq_adapter::{Config, ConfigOptional, IcqAdapter}; use drop_staking_base::{ error::icq_adapter::{ContractError, ContractResult}, msg::icq_adapter::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}, @@ -14,6 +15,7 @@ use neutron_sdk::bindings::{msg::NeutronMsg, query::NeutronQuery}; use std::{env, vec}; use crate::msg::Options; +use crate::store::DELEGATIONS_AND_BALANCES_QUERY_ID_CHUNK; const CONTRACT_NAME: &str = concat!("crates.io:drop-staking__", env!("CARGO_PKG_NAME")); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -25,27 +27,37 @@ pub fn instantiate( info: MessageInfo, msg: InstantiateMsg, ) -> ContractResult> { + let adapter: IcqAdapter = IcqAdapter::new(); let owner = msg.owner.unwrap_or(info.sender.to_string()); cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; cw_ownable::initialize_owner(deps.storage, deps.api, Some(owner.as_str()))?; let router = deps.api.addr_validate(&msg.router)?; + bech32::decode(&msg.ica).map_err(|_| ContractError::InvalidIca)?; let attrs = vec![ attr("action", "instantiate"), attr("router", router.to_string()), attr("owner", owner), + attr("ica", msg.ica.to_string()), ]; - CONFIG.save(deps.storage, &Config { router })?; + let config: Config = Config { + router, + remote_denom: msg.remote_denom, + ica: msg.ica, + options: msg.options, + }; + adapter.config.save(deps.storage, &config)?; Ok(response("instantiate", CONTRACT_NAME, attrs)) } #[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] -pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> ContractResult { +pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> ContractResult { match msg { - QueryMsg::Balances {} => query_balance(deps), - QueryMsg::Delegations {} => query_delegations(deps), - QueryMsg::NonNativeRewardsBalances {} => query_non_native_rewards_balances(deps), QueryMsg::Ownership {} => Ok(to_json_binary(&cw_ownable::get_ownership(deps.storage)?)?), - QueryMsg::Config {} => Ok(to_json_binary(&CONFIG.load(deps.storage)?)?), + QueryMsg::Config {} => { + let adapter: IcqAdapter = IcqAdapter::new(); + Ok(to_json_binary(&adapter.config.load(deps.storage)?)?) + } + QueryMsg::Extention(_) => todo!(), } } @@ -54,11 +66,11 @@ pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, - msg: ExecuteMsg, + msg: ExecuteMsg, ) -> ContractResult> { match msg { - ExecuteMsg::UpdateValidators { validators } => { - update_validators(deps, info, env, validators) + ExecuteMsg::UpdateValidatorSet { validators } => { + register_delegations_and_balance_query(deps, info, validators) } ExecuteMsg::UpdateConfig { new_config } => update_config(deps, info, new_config), ExecuteMsg::UpdateOwnership(action) => { @@ -66,10 +78,6 @@ pub fn execute( cw_ownable::update_ownership(deps.into_empty(), &env.block, &info.sender, action)?; Ok(response("update_ownership", CONTRACT_NAME, attrs)) } - ExecuteMsg::UpdateBalances { balances } => update_balances(deps, info, env, balances), - ExecuteMsg::UpdateDelegations { delegations } => { - update_delegations(deps, info, env, delegations) - } } } @@ -88,86 +96,95 @@ pub fn migrate( Ok(Response::new()) } -fn query_balance(deps: Deps) -> ContractResult { - let balance = BALANCES.load(deps.storage)?; - Ok(to_json_binary(&balance)?) -} - -fn query_delegations(deps: Deps) -> ContractResult { - let delegations = DELEGATIONS.load(deps.storage)?; - Ok(to_json_binary(&delegations)?) -} - -fn query_non_native_rewards_balances(deps: Deps) -> ContractResult { - let balances = NON_NATIVE_REWARD_BALANCES.load(deps.storage)?; - Ok(to_json_binary(&balances)?) -} - -fn update_balances( +pub fn update_config( deps: DepsMut, info: MessageInfo, - _env: Env, - balances: BalancesData, + new_config: ConfigOptional, ) -> ContractResult> { - let config = CONFIG.load(deps.storage)?; - ensure_eq!(info.sender, config.adapter, ContractError::Unauthorized {}); - let old_data = BALANCES.load(deps.storage)?; - ensure!( - balances.remote_height > old_data.remote_height, - ContractError::OutdatedData - ); - BALANCES.save(deps.storage, &balances)?; - Ok(Response::new()) + let adapter: IcqAdapter = IcqAdapter::new(); + let config = adapter.config.load(deps.storage)?; + cw_ownable::assert_owner(deps.storage, &info.sender)?; + let mut updated_config = Config { + remote_denom: config.remote_denom, + router: config.router, + ica: config.ica, + options: new_config.options.unwrap_or(config.options), + }; + let mut attrs = vec![attr("action", "update_config")]; + if let Some(ica) = new_config.ica { + bech32::decode(&ica).map_err(|_| ContractError::InvalidIca)?; + attrs.push(attr("ica", ica.clone())); + updated_config.ica = ica; + } + if let Some(router) = new_config.router { + let router = deps.api.addr_validate(&router)?; + attrs.push(attr("router", router.to_string())); + updated_config.router = router; + } + if let Some(remote_denom) = new_config.remote_denom { + attrs.push(attr("remote_denom", remote_denom.clone())); + updated_config.remote_denom = remote_denom; + } + adapter.config.save(deps.storage, &updated_config)?; + Ok(response("update_config", CONTRACT_NAME, attrs)) } -fn update_config( +fn register_delegations_and_balance_query( deps: DepsMut, info: MessageInfo, - new_config: ConfigOptional, + validators: Vec, ) -> ContractResult> { + let adapter: IcqAdapter = IcqAdapter::new(); + let config = adapter.config.load(deps.storage)?; cw_ownable::assert_owner(deps.storage, &info.sender)?; - let mut config = CONFIG.load(deps.storage)?; - if let Some(adapter) = new_config.adapter { - config.adapter = deps.api.addr_validate(&adapter)?; + cosmwasm_std::ensure!( + validators.len() < u16::MAX as usize, + StdError::generic_err("Too many validators provided") + ); + let current_queries: Vec = DELEGATIONS_AND_BALANCES_QUERY_ID_CHUNK + .keys(deps.storage, None, None, Order::Ascending) + .collect::>>()?; + let messages = current_queries + .iter() + .map(|query_id| { + DELEGATIONS_AND_BALANCES_QUERY_ID_CHUNK.remove(deps.storage, *query_id); + NeutronMsg::remove_interchain_query(*query_id) + }) + .collect::>(); + + let mut submessages = vec![]; + + for (i, chunk) in validators + .chunks(config.options.delegations_queries_chunk_size as usize) + .enumerate() + { + submessages.push(SubMsg::reply_on_success( + new_delegations_and_balance_query_msg( + config.options.connection_id.clone(), + config.ica.clone(), + config.remote_denom.clone(), + chunk.to_vec(), + config.options.update_period, + config.options.sdk_version.as_str(), + )?, + i as u64, + )); } - CONFIG.save(deps.storage, &config)?; - Ok(Response::new()) + + Ok(Response::new() + .add_messages(messages) + .add_submessages(submessages)) } -fn update_delegations( - deps: DepsMut, - info: MessageInfo, - _env: Env, - delegations: DelegationsData, -) -> ContractResult> { - let config = CONFIG.load(deps.storage)?; - ensure_eq!(info.sender, config.adapter, ContractError::Unauthorized {}); - let old_data = DELEGATIONS.load(deps.storage)?; - ensure!( - delegations.remote_height > old_data.remote_height, - ContractError::OutdatedData - ); - DELEGATIONS.save(deps.storage, &delegations)?; - Ok(Response::new()) +pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> StdResult { + register_delegations_and_balance_query_reply(deps, msg) } -fn update_validators( - deps: DepsMut, - _info: MessageInfo, - _env: Env, - validators: Vec, -) -> ContractResult> { - let config = CONFIG.load(deps.storage)?; - let res = response( - "update_validators", - CONTRACT_NAME, - [attr("validators", format!("{:?}", validators))], - ); - Ok(res.add_message(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.adapter.to_string(), - msg: to_json_binary( - &drop_staking_base::msg::icq_adapter::ExecuteMsg::UpdateValidatorSet { validators }, - )?, - funds: vec![], - }))) +pub fn register_delegations_and_balance_query_reply( + deps: DepsMut, + msg: Reply, +) -> StdResult { + let query_id = get_query_id(msg.result)?; + DELEGATIONS_AND_BALANCES_QUERY_ID_CHUNK.save(deps.storage, query_id, &msg.id)?; + Ok(Response::new()) } diff --git a/contracts/icq-adapter-kv/src/lib.rs b/contracts/icq-adapter-kv/src/lib.rs index fbedb827..f232e834 100644 --- a/contracts/icq-adapter-kv/src/lib.rs +++ b/contracts/icq-adapter-kv/src/lib.rs @@ -1,5 +1,6 @@ pub mod contract; pub mod msg; +pub mod store; // #[cfg(test)] // mod tests; diff --git a/contracts/icq-adapter-kv/src/msg.rs b/contracts/icq-adapter-kv/src/msg.rs index aa184185..553dd518 100644 --- a/contracts/icq-adapter-kv/src/msg.rs +++ b/contracts/icq-adapter-kv/src/msg.rs @@ -1,4 +1,9 @@ use cosmwasm_schema::cw_serde; #[cw_serde] -pub struct Options {} +pub struct Options { + pub delegations_queries_chunk_size: u32, + pub connection_id: String, + pub sdk_version: String, + pub update_period: u64, +} diff --git a/contracts/icq-adapter-kv/src/store.rs b/contracts/icq-adapter-kv/src/store.rs new file mode 100644 index 00000000..f2701d58 --- /dev/null +++ b/contracts/icq-adapter-kv/src/store.rs @@ -0,0 +1,4 @@ +use cw_storage_plus::Map; + +pub const DELEGATIONS_AND_BALANCES_QUERY_ID_CHUNK: Map = + Map::new("delegations_and_balances_query_id_chunk"); diff --git a/packages/base/src/error/icq_adapter.rs b/packages/base/src/error/icq_adapter.rs index 235eaeac..0c488896 100644 --- a/packages/base/src/error/icq_adapter.rs +++ b/packages/base/src/error/icq_adapter.rs @@ -1,5 +1,6 @@ use cosmwasm_std::StdError; use cw_ownable::OwnershipError; +use neutron_sdk::NeutronError; use thiserror::Error; #[derive(Error, Debug, PartialEq)] @@ -10,11 +11,17 @@ pub enum ContractError { #[error("{0}")] OwnershipError(#[from] OwnershipError), + #[error("{0}")] + NeutronError(#[from] NeutronError), + #[error("Semver parsing error: {0}")] SemVer(String), #[error("Unauthorized")] Unauthorized, + + #[error("Invalid Ica")] + InvalidIca, } impl From for ContractError { diff --git a/packages/base/src/msg/icq_adapter.rs b/packages/base/src/msg/icq_adapter.rs index d166bd1a..bccc856e 100644 --- a/packages/base/src/msg/icq_adapter.rs +++ b/packages/base/src/msg/icq_adapter.rs @@ -1,3 +1,4 @@ +use crate::state::icq_adapter::ConfigOptional; use cosmwasm_schema::cw_serde; #[cw_ownable::cw_ownable_query] @@ -10,19 +11,20 @@ pub enum QueryMsg { Extention(E), } +#[cw_ownable::cw_ownable_execute] #[cw_serde] -pub enum ExecuteMsg { +pub enum ExecuteMsg { UpdateValidatorSet { validators: Vec }, - UpdateBalances {}, - UpdateDelegations {}, - UpdateConfig {}, + UpdateConfig { new_config: ConfigOptional }, } #[cw_serde] pub struct InstantiateMsg { pub router: String, + pub ica: String, + pub remote_denom: String, pub owner: Option, - pub opts: O, + pub options: O, } #[cw_serde] diff --git a/packages/base/src/state/icq_adapter.rs b/packages/base/src/state/icq_adapter.rs index 7808db12..7d3199a2 100644 --- a/packages/base/src/state/icq_adapter.rs +++ b/packages/base/src/state/icq_adapter.rs @@ -1,21 +1,53 @@ use cosmwasm_schema::cw_serde; use cosmwasm_std::Addr; use cw_storage_plus::Item; +use serde::{de::DeserializeOwned, Serialize}; use crate::msg::icq_router::{BalancesData, DelegationsData}; #[cw_serde] pub struct Config { pub router: Addr, + pub ica: String, + pub remote_denom: String, pub options: E, } #[cw_serde] -pub struct ConfigOptional { +pub struct ConfigOptional { pub router: Option, + pub ica: Option, + pub remote_denom: Option, + pub options: Option, } -pub const CONFIG: Item = Item::new("config"); -pub const BALANCES: Item = Item::new("balances"); -pub const DELEGATIONS: Item = Item::new("delegations"); -pub const NON_NATIVE_REWARD_BALANCES: Item = Item::new("non_native_reward_balances"); +pub struct IcqAdapter<'a, T> +where + T: Serialize + DeserializeOwned + Clone, +{ + pub config: Item<'a, Config>, + pub balances: Item<'a, BalancesData>, + pub delegations: Item<'a, DelegationsData>, +} + +impl Default for IcqAdapter<'static, T> +where + T: Serialize + DeserializeOwned + Clone, +{ + fn default() -> Self { + Self::new() + } +} + +impl<'a, T> IcqAdapter<'a, T> +where + T: Serialize + DeserializeOwned + Clone, +{ + pub fn new() -> Self { + Self { + config: Item::new("config"), + balances: Item::new("balances"), + delegations: Item::new("delegations"), + } + } +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 7897a24d..628740b1 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.75.0" +channel = "1.79.0" From 652da11987f31fe877450e6ec794e8e7705ba783 Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Tue, 17 Dec 2024 17:23:43 +0100 Subject: [PATCH 10/14] wip --- contracts/icq-adapter-kv/src/contract.rs | 60 ++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/contracts/icq-adapter-kv/src/contract.rs b/contracts/icq-adapter-kv/src/contract.rs index 8ce1ac00..f7688d91 100644 --- a/contracts/icq-adapter-kv/src/contract.rs +++ b/contracts/icq-adapter-kv/src/contract.rs @@ -188,3 +188,63 @@ pub fn register_delegations_and_balance_query_reply( DELEGATIONS_AND_BALANCES_QUERY_ID_CHUNK.save(deps.storage, query_id, &msg.id)?; Ok(Response::new()) } + +#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] +pub fn sudo( + deps: DepsMut, + env: Env, + msg: SudoMsg, +) -> NeutronResult> { + let puppeteer_base = Puppeteer::default(); + deps.api.debug(&format!( + "WASMDEBUG: sudo call: {:?} block: {:?}", + msg, env.block + )); + match msg { + SudoMsg::Response { request, data } => sudo_response(deps, env, request, data), + SudoMsg::Error { request, details } => sudo_error(deps, env, request, details), + SudoMsg::Timeout { request } => sudo_timeout(deps, env, request), + SudoMsg::TxQueryResult { + query_id, + height, + data, + } => puppeteer_base.sudo_tx_query_result(deps, env, query_id, height, data), + SudoMsg::KVQueryResult { query_id } => { + let query_type = puppeteer_base.kv_queries.load(deps.storage, query_id)?; + let config = puppeteer_base.config.load(deps.storage)?; + deps.api + .debug(&format!("WASMDEBUG: KVQueryResult type {:?}", query_type)); + match query_type { + KVQueryType::DelegationsAndBalance => sudo_delegations_and_balance_kv_query_result( + deps, + env, + query_id, + &config.sdk_version, + ), + KVQueryType::NonNativeRewardsBalances => puppeteer_base.sudo_kv_query_result( + deps, + env, + query_id, + &config.sdk_version, + NON_NATIVE_REWARD_BALANCES, + ), + KVQueryType::UnbondingDelegations => { + puppeteer_base.sudo_unbonding_delegations_kv_query_result(deps, env, query_id) + } + } + } + SudoMsg::OpenAck { + port_id, + channel_id, + counterparty_channel_id, + counterparty_version, + } => puppeteer_base.sudo_open_ack( + deps, + env, + port_id, + channel_id, + counterparty_channel_id, + counterparty_version, + ), + } +} From ab5a54193417e6539bac6cc32f253c234baf055a Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Wed, 18 Dec 2024 07:36:01 +0100 Subject: [PATCH 11/14] wip --- Cargo.lock | 2 + contracts/icq-adapter-kv/.cargo/config | 2 +- contracts/icq-adapter-kv/Cargo.toml | 2 + ...chema.rs => drop-icq-adapter-kv-schema.rs} | 0 contracts/icq-adapter-kv/src/contract.rs | 111 +++++++----- contracts/icq-adapter-kv/src/store.rs | 167 +++++++++++++++++- contracts/icq-router/.cargo/config | 2 +- 7 files changed, 235 insertions(+), 51 deletions(-) rename contracts/icq-adapter-kv/src/bin/{drop-icq-router-schema.rs => drop-icq-adapter-kv-schema.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index 5614a665..8764cb6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -726,6 +726,7 @@ name = "drop-icq-adapter-kv" version = "1.0.0" dependencies = [ "bech32 0.11.0", + "cosmos-sdk-proto", "cosmwasm-schema", "cosmwasm-std", "cw-ownable", @@ -735,6 +736,7 @@ dependencies = [ "drop-helpers", "drop-staking-base", "neutron-sdk", + "prost", "semver", ] diff --git a/contracts/icq-adapter-kv/.cargo/config b/contracts/icq-adapter-kv/.cargo/config index 5d2a9bf7..f7b3db32 100644 --- a/contracts/icq-adapter-kv/.cargo/config +++ b/contracts/icq-adapter-kv/.cargo/config @@ -1,2 +1,2 @@ [alias] -schema = "run --bin drop-mirror-schema" +schema = "run --bin drop-adapter-kv-schema" diff --git a/contracts/icq-adapter-kv/Cargo.toml b/contracts/icq-adapter-kv/Cargo.toml index a582498c..ea395109 100644 --- a/contracts/icq-adapter-kv/Cargo.toml +++ b/contracts/icq-adapter-kv/Cargo.toml @@ -23,6 +23,8 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] [dependencies] +cosmos-sdk-proto = { workspace = true } +prost = { workspace = true } cosmwasm-schema = { workspace = true } cosmwasm-std = { workspace = true } cw-ownable = { workspace = true } diff --git a/contracts/icq-adapter-kv/src/bin/drop-icq-router-schema.rs b/contracts/icq-adapter-kv/src/bin/drop-icq-adapter-kv-schema.rs similarity index 100% rename from contracts/icq-adapter-kv/src/bin/drop-icq-router-schema.rs rename to contracts/icq-adapter-kv/src/bin/drop-icq-adapter-kv-schema.rs diff --git a/contracts/icq-adapter-kv/src/contract.rs b/contracts/icq-adapter-kv/src/contract.rs index f7688d91..e984a30f 100644 --- a/contracts/icq-adapter-kv/src/contract.rs +++ b/contracts/icq-adapter-kv/src/contract.rs @@ -11,11 +11,18 @@ use drop_staking_base::{ msg::icq_adapter::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}, }; use neutron_sdk::bindings::{msg::NeutronMsg, query::NeutronQuery}; +use neutron_sdk::interchain_queries::queries::get_raw_interchain_query_result; +use neutron_sdk::sudo::msg::SudoMsg; +use neutron_sdk::NeutronResult; use std::{env, vec}; use crate::msg::Options; -use crate::store::DELEGATIONS_AND_BALANCES_QUERY_ID_CHUNK; +use crate::store::{ + BalancesAndDelegations, BalancesAndDelegationsState, ResultReconstruct, + DELEGATIONS_AND_BALANCES, DELEGATIONS_AND_BALANCES_QUERY_ID_CHUNK, + LAST_COMPLETE_DELEGATIONS_AND_BALANCES_KEY, +}; const CONTRACT_NAME: &str = concat!("crates.io:drop-staking__", env!("CARGO_PKG_NAME")); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -195,56 +202,64 @@ pub fn sudo( env: Env, msg: SudoMsg, ) -> NeutronResult> { - let puppeteer_base = Puppeteer::default(); - deps.api.debug(&format!( - "WASMDEBUG: sudo call: {:?} block: {:?}", - msg, env.block - )); match msg { - SudoMsg::Response { request, data } => sudo_response(deps, env, request, data), - SudoMsg::Error { request, details } => sudo_error(deps, env, request, details), - SudoMsg::Timeout { request } => sudo_timeout(deps, env, request), - SudoMsg::TxQueryResult { - query_id, - height, - data, - } => puppeteer_base.sudo_tx_query_result(deps, env, query_id, height, data), SudoMsg::KVQueryResult { query_id } => { - let query_type = puppeteer_base.kv_queries.load(deps.storage, query_id)?; - let config = puppeteer_base.config.load(deps.storage)?; - deps.api - .debug(&format!("WASMDEBUG: KVQueryResult type {:?}", query_type)); - match query_type { - KVQueryType::DelegationsAndBalance => sudo_delegations_and_balance_kv_query_result( - deps, - env, - query_id, - &config.sdk_version, - ), - KVQueryType::NonNativeRewardsBalances => puppeteer_base.sudo_kv_query_result( - deps, - env, - query_id, - &config.sdk_version, - NON_NATIVE_REWARD_BALANCES, - ), - KVQueryType::UnbondingDelegations => { - puppeteer_base.sudo_unbonding_delegations_kv_query_result(deps, env, query_id) - } + sudo_delegations_and_balance_kv_query_result(deps, env, query_id) + } + _ => unreachable!(), + } +} + +fn sudo_delegations_and_balance_kv_query_result( + deps: DepsMut, + env: Env, + query_id: u64, +) -> NeutronResult> { + let adapter: IcqAdapter = IcqAdapter::new(); + let config = adapter.config.load(deps.storage)?; + let chunks_len = DELEGATIONS_AND_BALANCES_QUERY_ID_CHUNK + .keys(deps.storage, None, None, Order::Ascending) + .count(); + let chunk_id = DELEGATIONS_AND_BALANCES_QUERY_ID_CHUNK.load(deps.storage, query_id)?; + let (remote_height, kv_results) = { + let registered_query_result = get_raw_interchain_query_result(deps.as_ref(), query_id)?; + ( + registered_query_result.result.height, + registered_query_result.result.kv_results, + ) + }; + let data: BalancesAndDelegations = + ResultReconstruct::reconstruct(&kv_results, &config.options.sdk_version, None)?; + + let new_state = match DELEGATIONS_AND_BALANCES.may_load(deps.storage, &remote_height)? { + Some(mut state) => { + if !state.collected_chunks.contains(&chunk_id) { + state + .data + .delegations + .delegations + .extend(data.delegations.delegations); + state.collected_chunks.push(chunk_id); } + state + } + None => BalancesAndDelegationsState { + data, + remote_height, + local_height: env.block.height, + timestamp: env.block.time, + collected_chunks: vec![chunk_id], + }, + }; + if new_state.collected_chunks.len() == chunks_len { + let prev_key = LAST_COMPLETE_DELEGATIONS_AND_BALANCES_KEY + .load(deps.storage) + .unwrap_or_default(); + if prev_key < remote_height { + LAST_COMPLETE_DELEGATIONS_AND_BALANCES_KEY.save(deps.storage, &remote_height)?; } - SudoMsg::OpenAck { - port_id, - channel_id, - counterparty_channel_id, - counterparty_version, - } => puppeteer_base.sudo_open_ack( - deps, - env, - port_id, - channel_id, - counterparty_channel_id, - counterparty_version, - ), } + + DELEGATIONS_AND_BALANCES.save(deps.storage, &remote_height, &new_state)?; + Ok(Response::default()) } diff --git a/contracts/icq-adapter-kv/src/store.rs b/contracts/icq-adapter-kv/src/store.rs index f2701d58..c4293c3b 100644 --- a/contracts/icq-adapter-kv/src/store.rs +++ b/contracts/icq-adapter-kv/src/store.rs @@ -1,4 +1,169 @@ -use cw_storage_plus::Map; +use cosmos_sdk_proto::cosmos::staking::v1beta1::{ + Delegation, Params, Validator as CosmosValidator, +}; +use cosmwasm_schema::{cw_serde, serde::Serialize}; +use cosmwasm_std::{Addr, Decimal256, Timestamp, Uint128}; +use cw_storage_plus::{Item, Map}; +use drop_helpers::version::version_to_u32; +use neutron_sdk::bindings::types::StorageValue; +use neutron_sdk::{ + interchain_queries::v045::{helpers::deconstruct_account_denom_balance_key, types::Balances}, + NeutronError, NeutronResult, +}; +use prost::Message; +use std::ops::Div; +use std::str::FromStr; pub const DELEGATIONS_AND_BALANCES_QUERY_ID_CHUNK: Map = Map::new("delegations_and_balances_query_id_chunk"); + +pub const LAST_COMPLETE_DELEGATIONS_AND_BALANCES_KEY: Item = + Item::new("last_complete_delegations_and_balances_key"); + +pub const DELEGATIONS_AND_BALANCES: Map> = + Map::new("delegations_and_balances"); + +#[cw_serde] +pub struct BalancesAndDelegationsState { + pub data: X, + pub remote_height: u64, + pub local_height: u64, + pub timestamp: Timestamp, + pub collected_chunks: Vec, +} + +pub trait ResultReconstruct { + fn reconstruct( + storage_values: &[StorageValue], + version: &str, + denom: Option<&str>, + ) -> NeutronResult + where + Self: Sized; +} + +#[cw_serde] +pub struct MultiBalances { + pub coins: Vec, +} + +#[cw_serde] +pub struct BalancesAndDelegations { + pub balances: Balances, + pub delegations: Delegations, +} + +#[cw_serde] +pub struct Delegations { + pub delegations: Vec, +} + +#[cw_serde] +pub struct DropDelegation { + pub delegator: Addr, + /// A validator address (e.g. cosmosvaloper1...) + pub validator: String, + /// How much we have locked in the delegation + pub amount: cosmwasm_std::Coin, + /// How many shares the delegator has in the validator + pub share_ratio: Decimal256, +} + +impl ResultReconstruct for BalancesAndDelegations { + fn reconstruct( + storage_values: &[neutron_sdk::bindings::types::StorageValue], + version: &str, + _denom: Option<&str>, + ) -> NeutronResult { + let version = version_to_u32(version)?; + if storage_values.is_empty() { + return Err(NeutronError::InvalidQueryResultFormat( + "storage_values length is 0".into(), + )); + } + let mut coins: Vec = Vec::with_capacity(storage_values.len()); + let kv = &storage_values[0]; + if kv.value.len() > 0 { + let (_, denom) = deconstruct_account_denom_balance_key(kv.key.to_vec())?; + let amount: Uint128 = + Uint128::from_str(&String::from_utf8(kv.value.to_vec()).map_err(|_| { + NeutronError::InvalidQueryResultFormat("Invalid utf8".to_string()) + })?)?; + + coins.push(cosmwasm_std::Coin::new(amount.u128(), denom)); + } + let mut delegations: Vec = + Vec::with_capacity((storage_values.len() - 2) / 2); + // first StorageValue is denom + if !storage_values[1].value.is_empty() { + let denom = match version { + ver if ver >= version_to_u32("0.47.0")? => { + // Parse as Params and get bond_denom + Params::decode(storage_values[1].value.as_slice())?.bond_denom + } + // For versions below "0.47.0", parse as string + _ => from_json(&storage_values[1].value)?, + }; + for chunk in storage_values[2..].chunks(2) { + if chunk[0].value.is_empty() { + // Incoming delegation can actually be empty, this just means that delegation + // is not present on remote chain, which is to be expected. So, if it doesn't + // exist, we can safely skip this and following chunk. + continue; + } + let delegation_sdk: Delegation = Delegation::decode(chunk[0].value.as_slice())?; + + let mut delegation_std = DropDelegation { + delegator: Addr::unchecked(delegation_sdk.delegator_address.as_str()), + validator: delegation_sdk.validator_address, + amount: Default::default(), + share_ratio: Decimal256::one(), + }; + + if chunk[1].value.is_empty() { + // At this point, incoming validator cannot be empty, that would be invalid, + // because delegation is already defined, so, building `cosmwasm_std::Delegation` + // from this data is impossible, incoming data is corrupted.post + return Err(NeutronError::InvalidQueryResultFormat( + "validator is empty".into(), + )); + } + let validator: CosmosValidator = + CosmosValidator::decode(chunk[1].value.as_slice())?; + + let delegation_shares = Decimal256::from_atomics( + Uint128::from_str(&delegation_sdk.shares)?, + DECIMAL_PLACES, + )?; + + let delegator_shares = Decimal256::from_atomics( + Uint128::from_str(&validator.delegator_shares)?, + DECIMAL_PLACES, + )?; + + let validator_tokens = + Decimal256::from_atomics(Uint128::from_str(&validator.tokens)?, 0)?; + + // https://github.com/cosmos/cosmos-sdk/blob/35ae2c4c72d4aeb33447d5a7af23ca47f786606e/x/staking/keeper/querier.go#L463 + // delegated_tokens = quotient(delegation.shares * validator.tokens / validator.total_shares); + let delegated_tokens = Uint128::try_from( + delegation_shares + .checked_mul(validator_tokens)? + .div(delegator_shares) + .atomics() + / Uint256::from(DECIMAL_FRACTIONAL), + ) + .map_err(|err| NeutronError::Std(StdError::ConversionOverflow { source: err }))? + .u128(); + delegation_std.share_ratio = validator_tokens / delegator_shares; + delegation_std.amount = cosmwasm_std::Coin::new(delegated_tokens, &denom); + + delegations.push(delegation_std); + } + } + Ok(BalancesAndDelegations { + delegations: Delegations { delegations }, + balances: Balances { coins }, + }) + } +} diff --git a/contracts/icq-router/.cargo/config b/contracts/icq-router/.cargo/config index 5d2a9bf7..5b4833db 100644 --- a/contracts/icq-router/.cargo/config +++ b/contracts/icq-router/.cargo/config @@ -1,2 +1,2 @@ [alias] -schema = "run --bin drop-mirror-schema" +schema = "run --bin drop-router-schema" From 489d715fe45e824d351909e0f527fbfcb4b9d147 Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Wed, 18 Dec 2024 08:16:38 +0100 Subject: [PATCH 12/14] wip --- contracts/icq-adapter-kv/src/contract.rs | 4 +- contracts/icq-adapter-kv/src/store.rs | 39 ++++++++++++++++++- contracts/icq-router/src/contract.rs | 6 ++- contracts/mirror/src/contract.rs | 2 +- .../native-bond-provider/src/contract.rs | 4 +- contracts/proposal-votes-poc/src/contract.rs | 4 +- .../provider-proposals-poc/src/contract.rs | 4 +- contracts/pump/src/contract.rs | 4 +- contracts/puppeteer-initia/src/contract.rs | 10 ++--- contracts/puppeteer/src/contract.rs | 10 ++--- contracts/validators-stats/src/contract.rs | 4 +- 11 files changed, 64 insertions(+), 27 deletions(-) diff --git a/contracts/icq-adapter-kv/src/contract.rs b/contracts/icq-adapter-kv/src/contract.rs index e984a30f..55b0e3e1 100644 --- a/contracts/icq-adapter-kv/src/contract.rs +++ b/contracts/icq-adapter-kv/src/contract.rs @@ -231,7 +231,7 @@ fn sudo_delegations_and_balance_kv_query_result( let data: BalancesAndDelegations = ResultReconstruct::reconstruct(&kv_results, &config.options.sdk_version, None)?; - let new_state = match DELEGATIONS_AND_BALANCES.may_load(deps.storage, &remote_height)? { + let new_state = match DELEGATIONS_AND_BALANCES.may_load(deps.storage, remote_height)? { Some(mut state) => { if !state.collected_chunks.contains(&chunk_id) { state @@ -260,6 +260,6 @@ fn sudo_delegations_and_balance_kv_query_result( } } - DELEGATIONS_AND_BALANCES.save(deps.storage, &remote_height, &new_state)?; + DELEGATIONS_AND_BALANCES.save(deps.storage, remote_height, &new_state)?; Ok(Response::default()) } diff --git a/contracts/icq-adapter-kv/src/store.rs b/contracts/icq-adapter-kv/src/store.rs index c4293c3b..41248c6e 100644 --- a/contracts/icq-adapter-kv/src/store.rs +++ b/contracts/icq-adapter-kv/src/store.rs @@ -1,8 +1,9 @@ +use cosmos_sdk_proto::cosmos::base::v1beta1::Coin as CosmosCoin; use cosmos_sdk_proto::cosmos::staking::v1beta1::{ Delegation, Params, Validator as CosmosValidator, }; use cosmwasm_schema::{cw_serde, serde::Serialize}; -use cosmwasm_std::{Addr, Decimal256, Timestamp, Uint128}; +use cosmwasm_std::{from_json, Addr, Decimal256, StdError, Timestamp, Uint128, Uint256}; use cw_storage_plus::{Item, Map}; use drop_helpers::version::version_to_u32; use neutron_sdk::bindings::types::StorageValue; @@ -14,13 +15,16 @@ use prost::Message; use std::ops::Div; use std::str::FromStr; +pub const DECIMAL_PLACES: u32 = 18; +const DECIMAL_FRACTIONAL: u128 = 10u128.pow(DECIMAL_PLACES); + pub const DELEGATIONS_AND_BALANCES_QUERY_ID_CHUNK: Map = Map::new("delegations_and_balances_query_id_chunk"); pub const LAST_COMPLETE_DELEGATIONS_AND_BALANCES_KEY: Item = Item::new("last_complete_delegations_and_balances_key"); -pub const DELEGATIONS_AND_BALANCES: Map> = +pub const DELEGATIONS_AND_BALANCES: Map> = Map::new("delegations_and_balances"); #[cw_serde] @@ -167,3 +171,34 @@ impl ResultReconstruct for BalancesAndDelegations { }) } } + +impl ResultReconstruct for MultiBalances { + //TODO: fix in sdk and remove this + fn reconstruct( + storage_values: &[StorageValue], + version: &str, + _: Option<&str>, + ) -> NeutronResult { + let mut coins: Vec = Vec::with_capacity(storage_values.len()); + for kv in storage_values { + if kv.value.len() > 0 { + let (_, denom) = deconstruct_account_denom_balance_key(kv.key.to_vec())?; + let amount: Uint128 = match version_to_u32(version)? { + ver if ver >= version_to_u32("0.47.0")? => { + // Directly parse Uint128 from the string obtained from kv.value + Uint128::from_str(&String::from_utf8(kv.value.to_vec()).map_err(|_| { + NeutronError::InvalidQueryResultFormat("Invalid utf8".to_string()) + })?) + } + // For versions below "0.47.0", use the existing balance.amount + _ => { + let balance: CosmosCoin = CosmosCoin::decode(kv.value.as_slice())?; + Uint128::from_str(balance.amount.as_str()) + } + }?; + coins.push(cosmwasm_std::Coin::new(amount.u128(), denom)); + } + } + Ok(MultiBalances { coins }) + } +} diff --git a/contracts/icq-router/src/contract.rs b/contracts/icq-router/src/contract.rs index 72a8d89d..823bec3c 100644 --- a/contracts/icq-router/src/contract.rs +++ b/contracts/icq-router/src/contract.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{ attr, ensure, ensure_eq, from_json, to_json_binary, BankMsg, Binary, Coin, CosmosMsg, Deps, - DepsMut, Env, MessageInfo, Response, WasmMsg, + DepsMut, Empty, Env, MessageInfo, Response, WasmMsg, }; use drop_helpers::answer::response; use drop_staking_base::msg::icq_router::{BalancesData, DelegationsData}; @@ -166,7 +166,9 @@ fn update_validators( Ok(res.add_message(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: config.adapter.to_string(), msg: to_json_binary( - &drop_staking_base::msg::icq_adapter::ExecuteMsg::UpdateValidatorSet { validators }, + &drop_staking_base::msg::icq_adapter::ExecuteMsg::::UpdateValidatorSet { + validators, + }, )?, funds: vec![], }))) diff --git a/contracts/mirror/src/contract.rs b/contracts/mirror/src/contract.rs index fc243795..6b6da4cd 100644 --- a/contracts/mirror/src/contract.rs +++ b/contracts/mirror/src/contract.rs @@ -187,7 +187,7 @@ pub fn execute_update_bond( ) -> ContractResult> { cw_ownable::assert_owner(deps.storage, &info.sender)?; let mut bond = BONDS.load(deps.storage, id)?; - bond.receiver = receiver.clone(); + bond.receiver.clone_from(&receiver); bond.backup = backup .clone() .map(|a| deps.api.addr_validate(&a)) diff --git a/contracts/native-bond-provider/src/contract.rs b/contracts/native-bond-provider/src/contract.rs index f489df67..78104bb0 100644 --- a/contracts/native-bond-provider/src/contract.rs +++ b/contracts/native-bond-provider/src/contract.rs @@ -246,12 +246,12 @@ fn execute_update_config( } if let Some(port_id) = new_config.port_id { - state.port_id = port_id.clone(); + state.port_id.clone_from(&port_id); attrs.push(attr("port_id", port_id)); } if let Some(transfer_channel_id) = new_config.transfer_channel_id { - state.transfer_channel_id = transfer_channel_id.clone(); + state.transfer_channel_id.clone_from(&transfer_channel_id); attrs.push(attr("transfer_channel_id", transfer_channel_id)); } diff --git a/contracts/proposal-votes-poc/src/contract.rs b/contracts/proposal-votes-poc/src/contract.rs index fb53731a..b79e8fb3 100644 --- a/contracts/proposal-votes-poc/src/contract.rs +++ b/contracts/proposal-votes-poc/src/contract.rs @@ -125,12 +125,12 @@ fn execute_update_config( } if let Some(connection_id) = new_config.connection_id { - config.connection_id = connection_id.clone(); + config.connection_id.clone_from(&connection_id); attrs.push(attr("connection_id", connection_id)) } if let Some(port_id) = new_config.port_id { - config.port_id = port_id.clone(); + config.port_id.clone_from(&port_id); attrs.push(attr("port_id", port_id)) } diff --git a/contracts/provider-proposals-poc/src/contract.rs b/contracts/provider-proposals-poc/src/contract.rs index 1ebaae14..a8bb5592 100644 --- a/contracts/provider-proposals-poc/src/contract.rs +++ b/contracts/provider-proposals-poc/src/contract.rs @@ -211,12 +211,12 @@ fn execute_update_config( } if let Some(connection_id) = new_config.connection_id { - config.connection_id = connection_id.clone(); + config.connection_id.clone_from(&connection_id); attrs.push(attr("connection_id", connection_id)) } if let Some(port_id) = new_config.port_id { - config.port_id = port_id.clone(); + config.port_id.clone_from(&port_id); attrs.push(attr("port_id", port_id)) } diff --git a/contracts/pump/src/contract.rs b/contracts/pump/src/contract.rs index 0faa5fcf..b9804c34 100644 --- a/contracts/pump/src/contract.rs +++ b/contracts/pump/src/contract.rs @@ -149,7 +149,7 @@ fn execute_update_config( attrs.push(cosmwasm_std::attr("dest_port".to_string(), dest_port)); } if let Some(connection_id) = new_config.connection_id { - config.connection_id = connection_id.clone(); + config.connection_id.clone_from(&connection_id); attrs.push(cosmwasm_std::attr( "connection_id".to_string(), connection_id, @@ -167,7 +167,7 @@ fn execute_update_config( )); } if let Some(local_denom) = new_config.local_denom { - config.local_denom = local_denom.clone(); + config.local_denom.clone_from(&local_denom); attrs.push(cosmwasm_std::attr("local_denom".to_string(), local_denom)); } CONFIG.save(deps.storage, &config)?; diff --git a/contracts/puppeteer-initia/src/contract.rs b/contracts/puppeteer-initia/src/contract.rs index 842a157c..1704837a 100644 --- a/contracts/puppeteer-initia/src/contract.rs +++ b/contracts/puppeteer-initia/src/contract.rs @@ -268,17 +268,17 @@ fn execute_update_config( if !remote_denom.starts_with("move/") { return Err(ContractError::InvalidRemoteDenom); } - config.remote_denom = remote_denom.clone(); + config.remote_denom.clone_from(&remote_denom); attrs.push(attr("remote_denom", remote_denom)) } if let Some(connection_id) = new_config.connection_id { - config.connection_id = connection_id.clone(); + config.connection_id.clone_from(&connection_id); attrs.push(attr("connection_id", connection_id)) } if let Some(port_id) = new_config.port_id { - config.port_id = port_id.clone(); + config.port_id.clone_from(&port_id); attrs.push(attr("port_id", port_id)) } @@ -295,12 +295,12 @@ fn execute_update_config( } if let Some(transfer_channel_id) = new_config.transfer_channel_id { - config.transfer_channel_id = transfer_channel_id.clone(); + config.transfer_channel_id.clone_from(&transfer_channel_id); attrs.push(attr("transfer_channel_id", transfer_channel_id)) } if let Some(sdk_version) = new_config.sdk_version { - config.sdk_version = sdk_version.clone(); + config.sdk_version.clone_from(&sdk_version); attrs.push(attr("sdk_version", sdk_version)) } if let Some(timeout) = new_config.timeout { diff --git a/contracts/puppeteer/src/contract.rs b/contracts/puppeteer/src/contract.rs index 95e1ef7a..b953e427 100644 --- a/contracts/puppeteer/src/contract.rs +++ b/contracts/puppeteer/src/contract.rs @@ -287,17 +287,17 @@ fn execute_update_config( let mut attrs: Vec = Vec::new(); if let Some(remote_denom) = new_config.remote_denom { - config.remote_denom = remote_denom.clone(); + config.remote_denom.clone_from(&remote_denom); attrs.push(attr("remote_denom", remote_denom)) } if let Some(connection_id) = new_config.connection_id { - config.connection_id = connection_id.clone(); + config.connection_id.clone_from(&connection_id); attrs.push(attr("connection_id", connection_id)) } if let Some(port_id) = new_config.port_id { - config.port_id = port_id.clone(); + config.port_id.clone_from(&port_id); attrs.push(attr("port_id", port_id)) } @@ -314,12 +314,12 @@ fn execute_update_config( } if let Some(transfer_channel_id) = new_config.transfer_channel_id { - config.transfer_channel_id = transfer_channel_id.clone(); + config.transfer_channel_id.clone_from(&transfer_channel_id); attrs.push(attr("transfer_channel_id", transfer_channel_id)) } if let Some(sdk_version) = new_config.sdk_version { - config.sdk_version = sdk_version.clone(); + config.sdk_version.clone_from(&sdk_version); attrs.push(attr("sdk_version", sdk_version)) } if let Some(timeout) = new_config.timeout { diff --git a/contracts/validators-stats/src/contract.rs b/contracts/validators-stats/src/contract.rs index 13f114d3..0a4bb0ee 100644 --- a/contracts/validators-stats/src/contract.rs +++ b/contracts/validators-stats/src/contract.rs @@ -272,7 +272,7 @@ fn sudo_signing_info( if let Some(address) = valoper_address { let mut validator_state = get_validator_state(&deps, address.clone())?; - validator_state.valcons_address = info.address.clone(); + validator_state.valcons_address.clone_from(&info.address); validator_state.tombstone = if info.tombstoned { true } else { @@ -301,7 +301,7 @@ fn sudo_signing_info( // TODO: Implement tests fn calucalate_missed_blocks_percent( - all_missed_blocks: &Vec, + all_missed_blocks: &[MissedBlocks], missed_blocks: &mut MissedBlocks, address: String, missed_blocks_counter: u64, From 23ffb9a09d884291098197537c1dc23d9629d1e4 Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Wed, 18 Dec 2024 08:26:59 +0100 Subject: [PATCH 13/14] wip --- contracts/icq-adapter-kv/src/contract.rs | 4 ++-- contracts/icq-router/src/contract.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/icq-adapter-kv/src/contract.rs b/contracts/icq-adapter-kv/src/contract.rs index 55b0e3e1..95c7df9e 100644 --- a/contracts/icq-adapter-kv/src/contract.rs +++ b/contracts/icq-adapter-kv/src/contract.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{ - attr, ensure, ensure_eq, to_json_binary, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, - MessageInfo, Order, Reply, Response, StdError, StdResult, SubMsg, WasmMsg, + attr, to_json_binary, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Order, Reply, Response, + StdError, StdResult, SubMsg, }; use drop_helpers::answer::response; use drop_helpers::icq::new_delegations_and_balance_query_msg; diff --git a/contracts/icq-router/src/contract.rs b/contracts/icq-router/src/contract.rs index 823bec3c..2ccf9492 100644 --- a/contracts/icq-router/src/contract.rs +++ b/contracts/icq-router/src/contract.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{ - attr, ensure, ensure_eq, from_json, to_json_binary, BankMsg, Binary, Coin, CosmosMsg, Deps, - DepsMut, Empty, Env, MessageInfo, Response, WasmMsg, + attr, ensure, ensure_eq, to_json_binary, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, + MessageInfo, Response, WasmMsg, }; use drop_helpers::answer::response; use drop_staking_base::msg::icq_router::{BalancesData, DelegationsData}; From 5ef738a3203ceeb08be0e37aacc925d43bc682cc Mon Sep 17 00:00:00 2001 From: Sergey Ratiashvili Date: Thu, 19 Dec 2024 15:59:20 +0100 Subject: [PATCH 14/14] wip --- contracts/icq-adapter-kv/src/contract.rs | 37 ++++++++++++++++++++++-- contracts/icq-adapter-kv/src/store.rs | 17 ++--------- packages/base/src/msg/icq_router.rs | 2 +- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/contracts/icq-adapter-kv/src/contract.rs b/contracts/icq-adapter-kv/src/contract.rs index 95c7df9e..2b35d42e 100644 --- a/contracts/icq-adapter-kv/src/contract.rs +++ b/contracts/icq-adapter-kv/src/contract.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{ - attr, to_json_binary, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Order, Reply, Response, - StdError, StdResult, SubMsg, + attr, to_json_binary, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Order, Reply, + Response, StdError, StdResult, SubMsg, WasmMsg, }; use drop_helpers::answer::response; use drop_helpers::icq::new_delegations_and_balance_query_msg; @@ -251,15 +251,46 @@ fn sudo_delegations_and_balance_kv_query_result( collected_chunks: vec![chunk_id], }, }; + let mut msgs = vec![]; if new_state.collected_chunks.len() == chunks_len { let prev_key = LAST_COMPLETE_DELEGATIONS_AND_BALANCES_KEY .load(deps.storage) .unwrap_or_default(); if prev_key < remote_height { LAST_COMPLETE_DELEGATIONS_AND_BALANCES_KEY.save(deps.storage, &remote_height)?; + msgs.push(CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: config.router.to_string(), + msg: to_json_binary( + &drop_staking_base::msg::icq_router::ExecuteMsg::UpdateBalances { + balances: drop_staking_base::msg::icq_router::BalancesData { + balances: new_state.data.balances.clone(), + remote_height, + local_height: env.block.height, + timestamp: env.block.time, + }, + }, + )?, + funds: vec![], + })); + msgs.push(CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: config.router.to_string(), + msg: to_json_binary( + &drop_staking_base::msg::icq_router::ExecuteMsg::UpdateDelegations { + delegations: drop_staking_base::msg::icq_router::DelegationsData { + delegations: drop_staking_base::msg::icq_router::Delegations { + delegations: new_state.data.delegations.delegations.clone(), + }, + remote_height, + local_height: env.block.height, + timestamp: env.block.time, + }, + }, + )?, + funds: vec![], + })); } } DELEGATIONS_AND_BALANCES.save(deps.storage, remote_height, &new_state)?; - Ok(Response::default()) + Ok(Response::default().add_messages(msgs)) } diff --git a/contracts/icq-adapter-kv/src/store.rs b/contracts/icq-adapter-kv/src/store.rs index 41248c6e..3081afb6 100644 --- a/contracts/icq-adapter-kv/src/store.rs +++ b/contracts/icq-adapter-kv/src/store.rs @@ -59,18 +59,7 @@ pub struct BalancesAndDelegations { #[cw_serde] pub struct Delegations { - pub delegations: Vec, -} - -#[cw_serde] -pub struct DropDelegation { - pub delegator: Addr, - /// A validator address (e.g. cosmosvaloper1...) - pub validator: String, - /// How much we have locked in the delegation - pub amount: cosmwasm_std::Coin, - /// How many shares the delegator has in the validator - pub share_ratio: Decimal256, + pub delegations: Vec, } impl ResultReconstruct for BalancesAndDelegations { @@ -96,7 +85,7 @@ impl ResultReconstruct for BalancesAndDelegations { coins.push(cosmwasm_std::Coin::new(amount.u128(), denom)); } - let mut delegations: Vec = + let mut delegations: Vec = Vec::with_capacity((storage_values.len() - 2) / 2); // first StorageValue is denom if !storage_values[1].value.is_empty() { @@ -117,7 +106,7 @@ impl ResultReconstruct for BalancesAndDelegations { } let delegation_sdk: Delegation = Delegation::decode(chunk[0].value.as_slice())?; - let mut delegation_std = DropDelegation { + let mut delegation_std = drop_staking_base::msg::icq_router::DropDelegation { delegator: Addr::unchecked(delegation_sdk.delegator_address.as_str()), validator: delegation_sdk.validator_address, amount: Default::default(), diff --git a/packages/base/src/msg/icq_router.rs b/packages/base/src/msg/icq_router.rs index 1d5d801d..8bd65d62 100644 --- a/packages/base/src/msg/icq_router.rs +++ b/packages/base/src/msg/icq_router.rs @@ -1,6 +1,6 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; use cosmwasm_std::{Addr, Decimal256, Timestamp}; -use neutron_sdk::interchain_queries::v047::types::Balances; +use neutron_sdk::interchain_queries::v045::types::Balances; use crate::state::icq_router::ConfigOptional;