diff --git a/Cargo.lock b/Cargo.lock index 61dc33eb4f..d3bfd7346c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -907,9 +907,9 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.0.0-beta2" +version = "1.0.0-beta3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c16b255449b3f5cd7fa4b79acd5225b5185655261087a3d8aaac44f88a0e23e9" +checksum = "a380b87642204557629c9b72988c47b55fbfe6d474960adba56b22331504956a" dependencies = [ "digest 0.9.0", "ed25519-zebra", @@ -920,18 +920,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.0.0-beta2" +version = "1.0.0-beta3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abad1a6ff427a2f66890a4dce6354b4563cd07cee91a942300e011c921c09ed2" +checksum = "866713b2fe13f23038c7d8824c3059d1f28dd94685fb406d1533c4eeeefeefae" dependencies = [ "syn", ] [[package]] name = "cosmwasm-std" -version = "1.0.0-beta2" +version = "1.0.0-beta3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1660ee3d5734672e1eb4f0ceda403e2d83345e15143a48845f340f3252ce99a6" +checksum = "8dbb9939b31441dfa9af3ec9740c8a24d585688401eff1b6b386abb7ad0d10a8" dependencies = [ "base64", "cosmwasm-crypto", @@ -7275,7 +7275,9 @@ dependencies = [ "config", "cosmwasm-std", "cw-storage-plus", + "getrandom 0.2.3", "mixnet-contract", + "rand 0.8.4", "schemars", "serde", "thiserror", diff --git a/Makefile b/Makefile index 24f2606676..847e8332d3 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,36 @@ -all: clippy test fmt -clippy: clippy-main clippy-contracts clippy-wallet +all: clippy-all test fmt +happy: clippy-happy test fmt +clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet +clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet test: test-main test-contracts test-wallet fmt: fmt-main fmt-contracts fmt-wallet -clippy-main: +clippy-happy-main: cargo clippy -clippy-contracts: - cargo clippy --manifest-path contracts/Cargo.toml +clippy-happy-contracts: + cargo clippy --manifest-path contracts/Cargo.toml --target wasm32-unknown-unknown -clippy-wallet: +clippy-happy-wallet: cargo clippy --manifest-path nym-wallet/Cargo.toml +clippy-all-main: + cargo clippy --all-features -- -D warnings + +clippy-all-contracts: + cargo clippy --manifest-path contracts/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings + +clippy-all-wallet: + cargo clippy --manifest-path nym-wallet/Cargo.toml --all-features -- -D warnings + test-main: - cargo test + cargo test --all-features test-contracts: - cargo test --manifest-path contracts/Cargo.toml + cargo test --manifest-path contracts/Cargo.toml --all-features test-wallet: - cargo test --manifest-path nym-wallet/Cargo.toml + cargo test --manifest-path nym-wallet/Cargo.toml --all-features fmt-main: cargo fmt --all @@ -29,3 +40,6 @@ fmt-contracts: fmt-wallet: cargo fmt --manifest-path nym-wallet/Cargo.toml --all + +wasm: + RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown diff --git a/common/client-libs/validator-client/Cargo.toml b/common/client-libs/validator-client/Cargo.toml index f2b93c5ba6..236bd71754 100644 --- a/common/client-libs/validator-client/Cargo.toml +++ b/common/client-libs/validator-client/Cargo.toml @@ -33,7 +33,7 @@ prost = { version = "0.9", default-features = false, optional = true } flate2 = { version = "1.0.20", optional = true } sha2 = { version = "0.9.5", optional = true } itertools = { version = "0.10", optional = true } -cosmwasm-std = { version = "1.0.0-beta2", optional = true } +cosmwasm-std = { version = "1.0.0-beta3", optional = true } ts-rs = {version = "5.1", optional = true} [features] diff --git a/common/client-libs/validator-client/src/nymd/traits/vesting_signing_client.rs b/common/client-libs/validator-client/src/nymd/traits/vesting_signing_client.rs index 37b1d750b6..558a5af2ba 100644 --- a/common/client-libs/validator-client/src/nymd/traits/vesting_signing_client.rs +++ b/common/client-libs/validator-client/src/nymd/traits/vesting_signing_client.rs @@ -64,7 +64,8 @@ pub trait VestingSigningClient { async fn create_periodic_vesting_account( &self, - address: &str, + owner_address: &str, + staking_address: Option, start_time: Option, amount: Coin, ) -> Result; @@ -271,13 +272,15 @@ impl VestingSigningClient for NymdClient } async fn create_periodic_vesting_account( &self, - address: &str, + owner_address: &str, + staking_address: Option, start_time: Option, amount: Coin, ) -> Result { let fee = self.operation_fee(Operation::CreatePeriodicVestingAccount); let req = VestingExecuteMsg::CreateAccount { - address: address.to_string(), + owner_address: owner_address.to_string(), + staking_address, start_time, }; self.client diff --git a/common/mixnet-contract/Cargo.toml b/common/mixnet-contract/Cargo.toml index b7007a2666..6f17d0e879 100644 --- a/common/mixnet-contract/Cargo.toml +++ b/common/mixnet-contract/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cosmwasm-std = "1.0.0-beta2" +cosmwasm-std = "1.0.0-beta3" serde = { version = "1.0", features = ["derive"] } serde_repr = "0.1" diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index 9ea211b69c..5874784f8e 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -238,9 +238,9 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "cosmwasm-crypto" -version = "1.0.0-beta2" +version = "1.0.0-beta3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c16b255449b3f5cd7fa4b79acd5225b5185655261087a3d8aaac44f88a0e23e9" +checksum = "a380b87642204557629c9b72988c47b55fbfe6d474960adba56b22331504956a" dependencies = [ "digest 0.9.0", "ed25519-zebra", @@ -251,18 +251,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.0.0-beta2" +version = "1.0.0-beta3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abad1a6ff427a2f66890a4dce6354b4563cd07cee91a942300e011c921c09ed2" +checksum = "866713b2fe13f23038c7d8824c3059d1f28dd94685fb406d1533c4eeeefeefae" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.0.0-beta2" +version = "1.0.0-beta3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe52b19d45fe3f8359db6cc24df44dbe05e5ae32539afc0f5b7f790a21aa6fd0" +checksum = "818b928263c09a3269c2bed22494a62107a43ef87900e273af8ad2cb9f7e4440" dependencies = [ "schemars", "serde_json", @@ -270,9 +270,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.0.0-beta2" +version = "1.0.0-beta3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1660ee3d5734672e1eb4f0ceda403e2d83345e15143a48845f340f3252ce99a6" +checksum = "8dbb9939b31441dfa9af3ec9740c8a24d585688401eff1b6b386abb7ad0d10a8" dependencies = [ "base64", "cosmwasm-crypto", @@ -286,9 +286,9 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.0.0-beta2" +version = "1.0.0-beta3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3b4efe3b4f86df668520a02e9a29c23eea99b64dfcacb0e59b98346418af7f" +checksum = "b4a4e55f0d64fed54cd2202301b8d466af8de044589247dabd77a4222f52f749" dependencies = [ "cosmwasm-std", "serde", @@ -326,7 +326,7 @@ dependencies = [ "log", "nymsphinx-types", "pemstore", - "rand", + "rand 0.7.3", "subtle-encoding", "x25519-dalek", ] @@ -458,7 +458,7 @@ checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ "curve25519-dalek", "ed25519", - "rand", + "rand 0.7.3", "serde", "sha2", "zeroize", @@ -592,8 +592,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.10.2+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -856,8 +858,8 @@ dependencies = [ "cw-storage-plus", "fixed", "mixnet-contract", - "rand", - "rand_chacha", + "rand 0.7.3", + "rand_chacha 0.2.2", "schemars", "serde", "thiserror", @@ -1065,9 +1067,21 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ "getrandom 0.1.16", "libc", - "rand_chacha", + "rand_chacha 0.2.2", "rand_core 0.5.1", - "rand_hc", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.3", + "rand_hc 0.3.1", ] [[package]] @@ -1080,6 +1094,16 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.3", +] + [[package]] name = "rand_core" version = "0.5.1" @@ -1105,7 +1129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9e9532ada3929fb8b2e9dbe28d1e06c9b2cc65813f074fcb6bd5fbefeff9d56" dependencies = [ "num-traits", - "rand", + "rand 0.7.3", ] [[package]] @@ -1117,6 +1141,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core 0.6.3", +] + [[package]] name = "regex" version = "1.5.4" @@ -1297,7 +1330,7 @@ dependencies = [ "hmac", "lioness", "log", - "rand", + "rand 0.7.3", "rand_distr", "sha2", "subtle 2.4.1", @@ -1525,7 +1558,9 @@ dependencies = [ "config", "cosmwasm-std", "cw-storage-plus", + "getrandom 0.2.3", "mixnet-contract", + "rand 0.8.4", "schemars", "serde", "thiserror", diff --git a/contracts/bandwidth-claim/Cargo.toml b/contracts/bandwidth-claim/Cargo.toml index b9b3a15373..3480a608f1 100644 --- a/contracts/bandwidth-claim/Cargo.toml +++ b/contracts/bandwidth-claim/Cargo.toml @@ -8,18 +8,14 @@ edition = "2018" [lib] crate-type = ["cdylib", "rlib"] -[features] -# for more explicit tests, cargo test --features=backtraces -backtraces = ["cosmwasm-std/backtraces"] - [dev-dependencies] config = { path = "../../common/config"} [dependencies] bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" } -cosmwasm-std = "1.0.0-beta2" -cosmwasm-storage = "1.0.0-beta2" +cosmwasm-std = "1.0.0-beta3" +cosmwasm-storage = "1.0.0-beta3" schemars = "0.8" serde = { version = "1.0.103", default-features = false, features = ["derive"] } diff --git a/contracts/mixnet/Cargo.toml b/contracts/mixnet/Cargo.toml index 52710764cc..25de04f9db 100644 --- a/contracts/mixnet/Cargo.toml +++ b/contracts/mixnet/Cargo.toml @@ -15,17 +15,13 @@ exclude = [ [lib] crate-type = ["cdylib", "rlib"] -[features] -# for more explicit tests, cargo test --features=backtraces -backtraces = ["cosmwasm-std/backtraces"] - [dependencies] mixnet-contract = { path = "../../common/mixnet-contract" } config = { path = "../../common/config"} vesting-contract = { path = "../vesting" } -cosmwasm-std = "1.0.0-beta2" -cosmwasm-storage = "1.0.0-beta2" +cosmwasm-std = "1.0.0-beta3" +cosmwasm-storage = "1.0.0-beta3" cw-storage-plus = "0.10.3" bs58 = "0.4.0" @@ -34,7 +30,7 @@ serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.23" } [dev-dependencies] -cosmwasm-schema = "1.0.0-beta2" +cosmwasm-schema = "1.0.0-beta3" fixed = "1.1" rand_chacha = "0.2" rand = "0.7" diff --git a/contracts/vesting/Cargo.toml b/contracts/vesting/Cargo.toml index 21b5588e41..931d7c2d75 100644 --- a/contracts/vesting/Cargo.toml +++ b/contracts/vesting/Cargo.toml @@ -13,18 +13,15 @@ exclude = [ [lib] crate-type = ["cdylib", "rlib"] -[features] -# for more explicit tests, cargo test --features=backtraces -backtraces = ["cosmwasm-std/backtraces"] - [dependencies] mixnet-contract = { path = "../../common/mixnet-contract" } config = { path = "../../common/config" } -# this branch is identical to 0.14.1 with addition of updated k256 dependency required to help poor cargo choose correct version -cosmwasm-std = { version = "1.0.0-beta2", features = ["iterator"]} +cosmwasm-std = { version = "1.0.0-beta3"} cw-storage-plus = { version = "0.10.3", features = ["iterator"] } schemars = "0.8" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.23" } +rand = {version = "0.8.4", features = ["std_rng"]} +getrandom = { version = "0.2.3", features = ["js"]} \ No newline at end of file diff --git a/contracts/vesting/src/contract.rs b/contracts/vesting/src/contract.rs index 3ea02081ae..44a68ae853 100644 --- a/contracts/vesting/src/contract.rs +++ b/contracts/vesting/src/contract.rs @@ -45,9 +45,17 @@ pub fn execute( try_undelegate_from_mixnode(mix_identity, info, deps) } ExecuteMsg::CreateAccount { - address, + owner_address, + staking_address, start_time, - } => try_create_periodic_vesting_account(&address, start_time, info, env, deps), + } => try_create_periodic_vesting_account( + &owner_address, + staking_address, + start_time, + info, + env, + deps, + ), ExecuteMsg::WithdrawVestedCoins { amount } => { try_withdraw_vested_coins(amount, env, info, deps) } @@ -72,9 +80,84 @@ pub fn execute( ExecuteMsg::TrackUnbondGateway { owner, amount } => { try_track_unbond_gateway(&owner, amount, info, deps) } + ExecuteMsg::TransferOwnership { to_address } => { + try_transfer_ownership(to_address, info, deps) + } + ExecuteMsg::UpdateStakingAddress { to_address } => { + try_update_staking_address(to_address, info, deps) + } } } +// Only owner +pub fn try_withdraw_vested_coins( + amount: Coin, + env: Env, + info: MessageInfo, + deps: DepsMut, +) -> Result { + let address = info.sender.clone(); + let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?; + if address != account.owner_address() { + return Err(ContractError::NotOwner(account.owner_address().to_string())); + } + let spendable_coins = account.spendable_coins(None, &env, deps.storage)?; + if amount.amount <= spendable_coins.amount { + let new_balance = account + .load_balance(deps.storage)? + .u128() + .saturating_sub(amount.amount.u128()); + account.save_balance(Uint128::new(new_balance), deps.storage)?; + + let send_tokens = BankMsg::Send { + to_address: account.owner_address().as_str().to_string(), + amount: vec![amount], + }; + + Ok(Response::new() + .add_attribute("action", "whitdraw") + .add_message(send_tokens)) + } else { + Err(ContractError::InsufficientSpendable( + account.owner_address().as_str().to_string(), + spendable_coins.amount.u128(), + )) + } +} + +fn try_transfer_ownership( + to_address: String, + info: MessageInfo, + deps: DepsMut, +) -> Result { + let address = info.sender.clone(); + let to_address = deps.api.addr_validate(&to_address)?; + let mut account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?; + if address == account.owner_address() { + account.transfer_ownership(&to_address, deps.storage)?; + Ok(Response::default()) + } else { + Err(ContractError::NotOwner(account.owner_address().to_string())) + } +} + +fn try_update_staking_address( + to_address: Option, + info: MessageInfo, + deps: DepsMut, +) -> Result { + let address = info.sender.clone(); + let to_address = to_address.and_then(|x| deps.api.addr_validate(&x).ok()); + let mut account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?; + if address == account.owner_address() { + account.update_staking_address(to_address, deps.storage)?; + Ok(Response::default()) + } else { + Err(ContractError::NotOwner(account.owner_address().to_string())) + } +} + +// Owner or staking pub fn try_bond_gateway( gateway: Gateway, owner_signature: String, @@ -137,38 +220,6 @@ pub fn try_track_unbond_mixnode( Ok(Response::default()) } -pub fn try_withdraw_vested_coins( - amount: Coin, - env: Env, - info: MessageInfo, - deps: DepsMut, -) -> Result { - let address = info.sender.clone(); - let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?; - let spendable_coins = account.spendable_coins(None, &env, deps.storage)?; - if amount.amount <= spendable_coins.amount { - let new_balance = account - .load_balance(deps.storage)? - .u128() - .saturating_sub(amount.amount.u128()); - account.save_balance(Uint128::new(new_balance), deps.storage)?; - - let send_tokens = BankMsg::Send { - to_address: address.as_str().to_string(), - amount: vec![amount], - }; - - Ok(Response::new() - .add_attribute("action", "whitdraw") - .add_message(send_tokens)) - } else { - Err(ContractError::InsufficientSpendable( - address.as_str().to_string(), - spendable_coins.amount.u128(), - )) - } -} - fn try_track_undelegation( address: &str, mix_identity: IdentityKey, @@ -205,7 +256,8 @@ fn try_undelegate_from_mixnode( } fn try_create_periodic_vesting_account( - address: &str, + owner_address: &str, + staking_address: Option, start_time: Option, info: MessageInfo, env: Env, @@ -215,11 +267,17 @@ fn try_create_periodic_vesting_account( return Err(ContractError::NotAdmin(info.sender.as_str().to_string())); } let coin = validate_funds(&info.funds)?; - let address = deps.api.addr_validate(address)?; + let owner_address = deps.api.addr_validate(owner_address)?; + let staking_address = if let Some(staking_address) = staking_address { + Some(deps.api.addr_validate(&staking_address)?) + } else { + None + }; let start_time = start_time.unwrap_or_else(|| env.block.time.seconds()); let periods = populate_vesting_periods(start_time, NUM_VESTING_PERIODS); Account::new( - address, + owner_address, + staking_address, coin, Timestamp::from_seconds(start_time), periods, diff --git a/contracts/vesting/src/errors.rs b/contracts/vesting/src/errors.rs index 978dfc115b..3651ac48b5 100644 --- a/contracts/vesting/src/errors.rs +++ b/contracts/vesting/src/errors.rs @@ -38,4 +38,8 @@ pub enum ContractError { Underflow, #[error("No bond found for account {0}")] NoBondFound(String), + #[error("Action can only be executed by account owner -> {0}")] + NotOwner(String), + #[error("Invalid address: {0}")] + InvalidAddress(String), } diff --git a/contracts/vesting/src/messages.rs b/contracts/vesting/src/messages.rs index 2a12636419..fffec2ca15 100644 --- a/contracts/vesting/src/messages.rs +++ b/contracts/vesting/src/messages.rs @@ -18,7 +18,8 @@ pub enum ExecuteMsg { mix_identity: IdentityKey, }, CreateAccount { - address: String, + owner_address: String, + staking_address: Option, start_time: Option, }, WithdrawVestedCoins { @@ -47,6 +48,12 @@ pub enum ExecuteMsg { owner: String, amount: Coin, }, + TransferOwnership { + to_address: String, + }, + UpdateStakingAddress { + to_address: Option, + }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] diff --git a/contracts/vesting/src/storage.rs b/contracts/vesting/src/storage.rs index 0b3a3327bc..f8227d8581 100644 --- a/contracts/vesting/src/storage.rs +++ b/contracts/vesting/src/storage.rs @@ -5,8 +5,18 @@ use cw_storage_plus::Map; const ACCOUNTS: Map = Map::new("acc"); +pub fn delete_account(address: &Addr, storage: &mut dyn Storage) -> Result<(), ContractError> { + ACCOUNTS.remove(storage, address.to_owned()); + Ok(()) +} + pub fn save_account(account: &Account, storage: &mut dyn Storage) -> Result<(), ContractError> { - Ok(ACCOUNTS.save(storage, account.address(), account)?) + // This is a bit dirty, but its a simple way to allow for both staking account and owner to load it from storage + if let Some(staking_address) = account.staking_address() { + ACCOUNTS.save(storage, staking_address.to_owned(), account)?; + } + ACCOUNTS.save(storage, account.owner_address(), account)?; + Ok(()) } pub fn load_account( diff --git a/contracts/vesting/src/support/tests.rs b/contracts/vesting/src/support/tests.rs index 40686d794c..704fff6e3c 100644 --- a/contracts/vesting/src/support/tests.rs +++ b/contracts/vesting/src/support/tests.rs @@ -21,7 +21,8 @@ pub mod helpers { let periods = populate_vesting_periods(start_time.seconds(), NUM_VESTING_PERIODS); Account::new( - Addr::unchecked("fixture"), + Addr::unchecked("owner"), + Some(Addr::unchecked("staking")), Coin { amount: Uint128::new(1_000_000_000_000), denom: DENOM.to_string(), diff --git a/contracts/vesting/src/traits/vesting_account.rs b/contracts/vesting/src/traits/vesting_account.rs index 0efac7a570..a564cfd2f5 100644 --- a/contracts/vesting/src/traits/vesting_account.rs +++ b/contracts/vesting/src/traits/vesting_account.rs @@ -1,5 +1,5 @@ use crate::errors::ContractError; -use cosmwasm_std::{Coin, Env, Storage, Timestamp}; +use cosmwasm_std::{Addr, Coin, Env, Storage, Timestamp}; pub trait VestingAccount { // locked_coins returns the set of coins that are not spendable (can still be delegated tough) (i.e. locked), @@ -62,4 +62,14 @@ pub trait VestingAccount { env: &Env, storage: &dyn Storage, ) -> Result; + fn transfer_ownership( + &mut self, + to_address: &Addr, + storage: &mut dyn Storage, + ) -> Result<(), ContractError>; + fn update_staking_address( + &mut self, + to_address: Option, + storage: &mut dyn Storage, + ) -> Result<(), ContractError>; } diff --git a/contracts/vesting/src/vesting/account/delegating_account.rs b/contracts/vesting/src/vesting/account/delegating_account.rs index 002ad58b72..20b67c971e 100644 --- a/contracts/vesting/src/vesting/account/delegating_account.rs +++ b/contracts/vesting/src/vesting/account/delegating_account.rs @@ -2,6 +2,7 @@ use crate::errors::ContractError; use crate::traits::DelegatingAccount; use config::defaults::{DEFAULT_MIXNET_CONTRACT_ADDRESS, DENOM}; use cosmwasm_std::{wasm_execute, Coin, Env, Order, Response, Storage, Timestamp, Uint128}; +use cw_storage_plus::Map; use mixnet_contract::ExecuteMsg as MixnetExecuteMsg; use mixnet_contract::IdentityKey; @@ -19,14 +20,14 @@ impl DelegatingAccount for Account { if current_balance < coin.amount { return Err(ContractError::InsufficientBalance( - self.address.as_str().to_string(), + self.owner_address().as_str().to_string(), current_balance.u128(), )); } let msg = MixnetExecuteMsg::DelegateToMixnodeOnBehalf { mix_identity: mix_identity.clone(), - delegate: self.address().into_string(), + delegate: self.owner_address().into_string(), }; let delegate_to_mixnode = wasm_execute(DEFAULT_MIXNET_CONTRACT_ADDRESS, &msg, vec![coin.clone()])?; @@ -44,14 +45,14 @@ impl DelegatingAccount for Account { ) -> Result { if !self.any_delegation_for_mix(&mix_identity, storage) { return Err(ContractError::NoSuchDelegation( - self.address(), + self.owner_address(), mix_identity, )); } let msg = MixnetExecuteMsg::UndelegateFromMixnodeOnBehalf { mix_identity, - delegate: self.address().into_string(), + delegate: self.owner_address().into_string(), }; let undelegate_from_mixnode = wasm_execute( DEFAULT_MIXNET_CONTRACT_ADDRESS, @@ -76,17 +77,17 @@ impl DelegatingAccount for Account { storage: &mut dyn Storage, ) -> Result<(), ContractError> { let delegation_key = (mix_identity.as_bytes(), block_time.seconds()); + let delegations_storage_key = self.delegations_key(); + let delegations: Map<(&[u8], u64), Uint128> = Map::new(&delegations_storage_key); - let new_delegation = if let Some(existing_delegation) = - self.delegations().may_load(storage, delegation_key)? - { - existing_delegation + delegation.amount - } else { - delegation.amount - }; + let new_delegation = + if let Some(existing_delegation) = delegations.may_load(storage, delegation_key)? { + existing_delegation + delegation.amount + } else { + delegation.amount + }; - self.delegations() - .save(storage, delegation_key, &new_delegation)?; + delegations.save(storage, delegation_key, &new_delegation)?; let new_balance = Uint128::new(current_balance.u128() - delegation.amount.u128()); @@ -102,10 +103,11 @@ impl DelegatingAccount for Account { storage: &mut dyn Storage, ) -> Result<(), ContractError> { let mix_bytes = mix_identity.as_bytes(); + let delegations_key = self.delegations_key(); + let delegations: Map<(&[u8], u64), Uint128> = Map::new(&delegations_key); // Iterate over keys matching the prefix and remove them from the map - let block_times = self - .delegations() + let block_times = delegations .prefix_de(mix_bytes) .keys_de(storage, None, None, Order::Ascending) // Scan will blow up on first error @@ -113,7 +115,7 @@ impl DelegatingAccount for Account { .collect::>(); for t in block_times { - self.delegations().remove(storage, (mix_bytes, t)) + delegations.remove(storage, (mix_bytes, t)) } let new_balance = Uint128::new(self.load_balance(storage)?.u128() + amount.amount.u128()); diff --git a/contracts/vesting/src/vesting/account/gateway_bonding_account.rs b/contracts/vesting/src/vesting/account/gateway_bonding_account.rs index f210f7d53b..b4100557b2 100644 --- a/contracts/vesting/src/vesting/account/gateway_bonding_account.rs +++ b/contracts/vesting/src/vesting/account/gateway_bonding_account.rs @@ -20,14 +20,14 @@ impl GatewayBondingAccount for Account { if current_balance < pledge.amount { return Err(ContractError::InsufficientBalance( - self.address.as_str().to_string(), + self.owner_address().as_str().to_string(), current_balance.u128(), )); } let pledge_data = if self.load_gateway_pledge(storage)?.is_some() { return Err(ContractError::AlreadyBonded( - self.address.as_str().to_string(), + self.owner_address().as_str().to_string(), )); } else { PledgeData { @@ -38,7 +38,7 @@ impl GatewayBondingAccount for Account { let msg = MixnetExecuteMsg::BondGatewayOnBehalf { gateway, - owner: self.address().into_string(), + owner: self.owner_address().into_string(), owner_signature, }; @@ -56,7 +56,7 @@ impl GatewayBondingAccount for Account { fn try_unbond_gateway(&self, storage: &dyn Storage) -> Result { let msg = MixnetExecuteMsg::UnbondGatewayOnBehalf { - owner: self.address().into_string(), + owner: self.owner_address().into_string(), }; if let Some(_bond) = self.load_gateway_pledge(storage)? { @@ -67,7 +67,7 @@ impl GatewayBondingAccount for Account { .add_message(unbond_msg)) } else { Err(ContractError::NoBondFound( - self.address.as_str().to_string(), + self.owner_address().as_str().to_string(), )) } } @@ -80,7 +80,7 @@ impl GatewayBondingAccount for Account { let new_balance = Uint128::new(self.load_balance(storage)?.u128() + amount.amount.u128()); self.save_balance(new_balance, storage)?; - self.remove_gateway_bond(storage)?; + self.remove_gateway_pledge(storage)?; Ok(()) } } diff --git a/contracts/vesting/src/vesting/account/mixnode_bonding_account.rs b/contracts/vesting/src/vesting/account/mixnode_bonding_account.rs index 12ed16ef8e..e62f9fea00 100644 --- a/contracts/vesting/src/vesting/account/mixnode_bonding_account.rs +++ b/contracts/vesting/src/vesting/account/mixnode_bonding_account.rs @@ -20,14 +20,14 @@ impl MixnodeBondingAccount for Account { if current_balance < pledge.amount { return Err(ContractError::InsufficientBalance( - self.address.as_str().to_string(), + self.owner_address().as_str().to_string(), current_balance.u128(), )); } let pledge_data = if self.load_mixnode_pledge(storage)?.is_some() { return Err(ContractError::AlreadyBonded( - self.address.as_str().to_string(), + self.owner_address().as_str().to_string(), )); } else { PledgeData { @@ -38,7 +38,7 @@ impl MixnodeBondingAccount for Account { let msg = MixnetExecuteMsg::BondMixnodeOnBehalf { mix_node, - owner: self.address().into_string(), + owner: self.owner_address().into_string(), owner_signature, }; @@ -56,7 +56,7 @@ impl MixnodeBondingAccount for Account { fn try_unbond_mixnode(&self, storage: &dyn Storage) -> Result { let msg = MixnetExecuteMsg::UnbondMixnodeOnBehalf { - owner: self.address().into_string(), + owner: self.owner_address().into_string(), }; if self.load_mixnode_pledge(storage)?.is_some() { @@ -67,7 +67,7 @@ impl MixnodeBondingAccount for Account { .add_message(unbond_msg)) } else { Err(ContractError::NoBondFound( - self.address.as_str().to_string(), + self.owner_address().as_str().to_string(), )) } } @@ -80,7 +80,7 @@ impl MixnodeBondingAccount for Account { let new_balance = Uint128::new(self.load_balance(storage)?.u128() + amount.amount.u128()); self.save_balance(new_balance, storage)?; - self.remove_mixnode_bond(storage)?; + self.remove_mixnode_pledge(storage)?; Ok(()) } } diff --git a/contracts/vesting/src/vesting/account/mod.rs b/contracts/vesting/src/vesting/account/mod.rs index db4ad86487..424a6ca27f 100644 --- a/contracts/vesting/src/vesting/account/mod.rs +++ b/contracts/vesting/src/vesting/account/mod.rs @@ -5,6 +5,8 @@ use crate::storage::save_account; use cosmwasm_std::{Addr, Coin, Order, Storage, Timestamp, Uint128}; use cw_storage_plus::{Item, Map}; use mixnet_contract::IdentityKey; +use rand::rngs::StdRng; +use rand::{RngCore, SeedableRng}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -18,44 +20,75 @@ const BALANCE_SUFFIX: &str = "ba"; const PLEDGE_SUFFIX: &str = "bo"; const GATEWAY_SUFFIX: &str = "ga"; +fn generate_storage_key(b: &[u8], storage: &dyn Storage) -> Result { + let mut rng = StdRng::seed_from_u64(b.iter().fold(0, |acc, x| acc + *x as u64)); + // Be paranoid and check for collisions + loop { + let key = rng.next_u64().to_string(); + let balance_key = format!("{}{}", key, BALANCE_SUFFIX); + let balance: Item = Item::new(&balance_key); + if balance.may_load(storage)?.is_none() { + return Ok(key); + } + } +} + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct Account { - address: Addr, + owner_address: Addr, + staking_address: Option, start_time: Timestamp, periods: Vec, coin: Coin, - delegations_key: String, - balance_key: String, - mixnode_pledge_key: String, - gateway_pledge_key: String, + storage_key: String, } impl Account { pub fn new( - address: Addr, + owner_address: Addr, + staking_address: Option, coin: Coin, start_time: Timestamp, periods: Vec, storage: &mut dyn Storage, ) -> Result { + let storage_key = generate_storage_key(owner_address.as_bytes(), storage)?; let amount = coin.amount; let account = Account { - address: address.to_owned(), + owner_address, + staking_address, start_time, periods, coin, - delegations_key: format!("{}_{}", address, DELEGATIONS_SUFFIX), - balance_key: format!("{}_{}", address, BALANCE_SUFFIX), - mixnode_pledge_key: format!("{}_{}", address, PLEDGE_SUFFIX), - gateway_pledge_key: format!("{}_{}", address, GATEWAY_SUFFIX), + storage_key, }; save_account(&account, storage)?; account.save_balance(amount, storage)?; Ok(account) } - pub fn address(&self) -> Addr { - self.address.clone() + pub fn delegations_key(&self) -> String { + format!("{}{}", self.storage_key, DELEGATIONS_SUFFIX) + } + + pub fn balance_key(&self) -> String { + format!("{}{}", self.storage_key, BALANCE_SUFFIX) + } + + pub fn mixnode_pledge_key(&self) -> String { + format!("{}{}", self.storage_key, PLEDGE_SUFFIX) + } + + pub fn gateway_pledge_key(&self) -> String { + format!("{}{}", self.storage_key, GATEWAY_SUFFIX) + } + + pub fn owner_address(&self) -> Addr { + self.owner_address.clone() + } + + pub fn staking_address(&self) -> Option<&Addr> { + self.staking_address.as_ref() } #[allow(dead_code)] @@ -100,10 +133,9 @@ impl Account { } pub fn load_balance(&self, storage: &dyn Storage) -> Result { - Ok(self - .balance() - .may_load(storage)? - .unwrap_or_else(Uint128::zero)) + let key = self.balance_key(); + let balance = Item::new(&key); + Ok(balance.may_load(storage)?.unwrap_or_else(Uint128::zero)) } pub fn save_balance( @@ -111,18 +143,18 @@ impl Account { amount: Uint128, storage: &mut dyn Storage, ) -> Result<(), ContractError> { - Ok(self.balance().save(storage, &amount)?) - } - - fn balance(&self) -> Item { - Item::new(self.balance_key.as_ref()) + let key = self.balance_key(); + let balance = Item::new(&key); + Ok(balance.save(storage, &amount)?) } pub fn load_mixnode_pledge( &self, storage: &dyn Storage, ) -> Result, ContractError> { - Ok(self.mixnode_pledge().may_load(storage)?) + let key = self.mixnode_pledge_key(); + let mixnode_pledge = Item::new(&key); + Ok(mixnode_pledge.may_load(storage)?) } pub fn save_mixnode_pledge( @@ -130,23 +162,25 @@ impl Account { pledge: PledgeData, storage: &mut dyn Storage, ) -> Result<(), ContractError> { - Ok(self.mixnode_pledge().save(storage, &pledge)?) + let key = self.mixnode_pledge_key(); + let mixnode_pledge = Item::new(&key); + Ok(mixnode_pledge.save(storage, &pledge)?) } - pub fn remove_mixnode_bond(&self, storage: &mut dyn Storage) -> Result<(), ContractError> { - self.mixnode_pledge().remove(storage); + pub fn remove_mixnode_pledge(&self, storage: &mut dyn Storage) -> Result<(), ContractError> { + let key = self.mixnode_pledge_key(); + let mixnode_pledge: Item = Item::new(&key); + mixnode_pledge.remove(storage); Ok(()) } - fn mixnode_pledge(&self) -> Item { - Item::new(self.mixnode_pledge_key.as_ref()) - } - pub fn load_gateway_pledge( &self, storage: &dyn Storage, ) -> Result, ContractError> { - Ok(self.gateway_pledge().may_load(storage)?) + let key = self.gateway_pledge_key(); + let gateway_pledge = Item::new(&key); + Ok(gateway_pledge.may_load(storage)?) } pub fn save_gateway_pledge( @@ -154,25 +188,23 @@ impl Account { pledge: PledgeData, storage: &mut dyn Storage, ) -> Result<(), ContractError> { - Ok(self.gateway_pledge().save(storage, &pledge)?) + let key = self.gateway_pledge_key(); + let gateway_pledge = Item::new(&key); + Ok(gateway_pledge.save(storage, &pledge)?) } - pub fn remove_gateway_bond(&self, storage: &mut dyn Storage) -> Result<(), ContractError> { - self.gateway_pledge().remove(storage); + pub fn remove_gateway_pledge(&self, storage: &mut dyn Storage) -> Result<(), ContractError> { + let key = self.gateway_pledge_key(); + let gateway_pledge: Item = Item::new(&key); + gateway_pledge.remove(storage); Ok(()) } - fn gateway_pledge(&self) -> Item { - Item::new(self.gateway_pledge_key.as_ref()) - } - - fn delegations(&self) -> Map<(&[u8], u64), Uint128> { - Map::new(self.delegations_key.as_ref()) - } - // Returns block_time part of the delegation key pub fn delegation_keys_for_mix(&self, mix: &str, storage: &dyn Storage) -> Vec { - self.delegations() + let key = self.delegations_key(); + let delegations: Map<(&[u8], u64), Uint128> = Map::new(&key); + delegations .prefix_de(mix.as_bytes()) .keys_de(storage, None, None, Order::Ascending) // Scan will blow up on first error @@ -191,10 +223,12 @@ impl Account { ) -> Result, ContractError> { let mix_bytes = mix.as_bytes(); let keys = self.delegation_keys_for_mix(&mix, storage); + let delegations_key = self.delegations_key(); + let delegations: Map<(&[u8], u64), Uint128> = Map::new(&delegations_key); let mut delegation_amounts = Vec::new(); for key in keys { - delegation_amounts.push(self.delegations().load(storage, (mix_bytes, key))?) + delegation_amounts.push(delegations.load(storage, (mix_bytes, key))?) } Ok(delegation_amounts) @@ -213,8 +247,9 @@ impl Account { } pub fn total_delegations(&self, storage: &dyn Storage) -> Result { - Ok(self - .delegations() + let delegations_key = self.delegations_key(); + let delegations: Map<(&[u8], u64), Uint128> = Map::new(&delegations_key); + Ok(delegations .range(storage, None, None, Order::Ascending) .scan((), |_, x| x.ok()) .fold(Uint128::zero(), |acc, (_, x)| acc + x)) diff --git a/contracts/vesting/src/vesting/account/vesting_account.rs b/contracts/vesting/src/vesting/account/vesting_account.rs index 12080f0cae..00ffdac957 100644 --- a/contracts/vesting/src/vesting/account/vesting_account.rs +++ b/contracts/vesting/src/vesting/account/vesting_account.rs @@ -1,8 +1,10 @@ use crate::contract::NUM_VESTING_PERIODS; use crate::errors::ContractError; +use crate::storage::{delete_account, save_account}; use crate::traits::VestingAccount; use config::defaults::DENOM; -use cosmwasm_std::{Coin, Env, Order, Storage, Timestamp, Uint128}; +use cosmwasm_std::{Addr, Coin, Env, Order, Storage, Timestamp, Uint128}; +use cw_storage_plus::Map; use super::Account; @@ -113,9 +115,10 @@ impl VestingAccount for Account { let period = self.get_current_vesting_period(block_time); let max_vested = self.tokens_per_period()? * period as u128; let start_time = self.periods[period].start_time; + let delegations_key = self.delegations_key(); + let delegations: Map<(&[u8], u64), Uint128> = Map::new(&delegations_key); - let delegations_keys = self - .delegations() + let delegations_keys = delegations .keys_de(storage, None, None, Order::Ascending) .scan((), |_, x| x.ok()) .filter(|(_mix, block_time)| *block_time < start_time) @@ -124,7 +127,7 @@ impl VestingAccount for Account { let mut amount = Uint128::zero(); for (mix, block_time) in delegations_keys { - amount += self.delegations().load(storage, (&mix, block_time))? + amount += delegations.load(storage, (&mix, block_time))? } amount = Uint128::new(amount.u128().min(max_vested)); @@ -209,4 +212,28 @@ impl VestingAccount for Account { }) } } + + fn transfer_ownership( + &mut self, + to_address: &Addr, + storage: &mut dyn Storage, + ) -> Result<(), ContractError> { + delete_account(&self.owner_address(), storage)?; + self.owner_address = to_address.to_owned(); + save_account(self, storage)?; + Ok(()) + } + + fn update_staking_address( + &mut self, + to_address: Option, + storage: &mut dyn Storage, + ) -> Result<(), ContractError> { + if let Some(staking_address) = self.staking_address() { + delete_account(staking_address, storage)?; + } + self.staking_address = to_address; + save_account(self, storage)?; + Ok(()) + } } diff --git a/contracts/vesting/src/vesting/mod.rs b/contracts/vesting/src/vesting/mod.rs index d9b2749c20..35d6d03d08 100644 --- a/contracts/vesting/src/vesting/mod.rs +++ b/contracts/vesting/src/vesting/mod.rs @@ -36,35 +36,132 @@ pub fn populate_vesting_periods(start_time: u64, n: usize) -> Vec #[cfg(test)] mod tests { - use crate::contract::{NUM_VESTING_PERIODS, VESTING_PERIOD}; + use crate::contract::{execute, ADMIN_ADDRESS, NUM_VESTING_PERIODS, VESTING_PERIOD}; + use crate::messages::ExecuteMsg; use crate::storage::load_account; use crate::support::tests::helpers::{init_contract, vesting_account_fixture}; use crate::traits::DelegatingAccount; use crate::traits::VestingAccount; use crate::traits::{GatewayBondingAccount, MixnodeBondingAccount}; use config::defaults::DENOM; - use cosmwasm_std::testing::mock_env; - use cosmwasm_std::{Addr, Coin, Timestamp, Uint128}; + use cosmwasm_std::testing::{mock_env, mock_info}; + use cosmwasm_std::{coins, Addr, Coin, Timestamp, Uint128}; use mixnet_contract::{Gateway, MixNode}; #[test] fn test_account_creation() { let mut deps = init_contract(); let env = mock_env(); - let account = vesting_account_fixture(&mut deps.storage, &env); - let created_account = load_account(&account.address(), &deps.storage).unwrap(); - let created_account_test = - load_account(&Addr::unchecked("fixture"), &deps.storage).unwrap(); - assert_eq!(Some(&account), created_account.as_ref()); - assert_eq!(Some(&account), created_account_test.as_ref()); + let info = mock_info("not_admin", &coins(1_000_000_000_000, DENOM)); + let msg = ExecuteMsg::CreateAccount { + owner_address: "owner".to_string(), + staking_address: Some("staking".to_string()), + start_time: None, + }; + let response = execute(deps.as_mut(), env.clone(), info, msg.clone()); + assert!(response.is_err()); + + let info = mock_info(ADMIN_ADDRESS, &coins(1_000_000_000_000, DENOM)); + let _response = execute(deps.as_mut(), env.clone(), info, msg.clone()); + let created_account = load_account(&Addr::unchecked("owner"), &deps.storage) + .unwrap() + .unwrap(); + let created_account_test_by_staking = + load_account(&Addr::unchecked("staking"), &deps.storage) + .unwrap() + .unwrap(); + assert_eq!(created_account_test_by_staking, created_account); assert_eq!( - account.load_balance(&deps.storage).unwrap(), + created_account.load_balance(&deps.storage).unwrap(), Uint128::new(1_000_000_000_000) ); + // Test key collision avoidance + + let account_again = vesting_account_fixture(&mut deps.storage, &env); assert_eq!( - account.load_balance(&deps.storage).unwrap(), - Uint128::new(1_000_000_000_000) - ) + created_account.balance_key(), + "5032709489228919411ba".to_string() + ); + assert_ne!(created_account.balance_key(), account_again.balance_key()); + } + + #[test] + fn test_ownership_transfer() { + let mut deps = init_contract(); + let mut env = mock_env(); + let info = mock_info("owner", &[]); + let account = vesting_account_fixture(&mut deps.storage, &env); + let msg = ExecuteMsg::TransferOwnership { + to_address: "new_owner".to_string(), + }; + let _response = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()).unwrap(); + let new_owner_account = load_account(&Addr::unchecked("new_owner"), &deps.storage) + .unwrap() + .unwrap(); + assert_eq!( + new_owner_account.load_balance(&deps.storage), + account.load_balance(&deps.storage) + ); + + // Check old account is gone + let old_owner_account = load_account(&Addr::unchecked("owner"), &deps.storage).unwrap(); + assert!(old_owner_account.is_none()); + + // Not the owner + let response = execute(deps.as_mut(), env.clone(), info.clone(), msg); + assert!(response.is_err()); + + let info = mock_info("new_owner", &[]); + let msg = ExecuteMsg::UpdateStakingAddress { + to_address: Some("new_staking".to_string()), + }; + let _response = execute(deps.as_mut(), env.clone(), info, msg).unwrap(); + let new_staking_account = load_account(&Addr::unchecked("new_staking"), &deps.storage) + .unwrap() + .unwrap(); + assert_eq!(new_staking_account.owner_address(), "new_owner".to_string()); + + let old_staking_account = load_account(&Addr::unchecked("staking"), &deps.storage).unwrap(); + assert!(old_staking_account.is_none()); + + let msg = ExecuteMsg::WithdrawVestedCoins { + amount: Coin { + amount: Uint128::new(1), + denom: "nym".to_string(), + }, + }; + let info = mock_info("new_owner", &[]); + env.block.time = Timestamp::from_nanos(env.block.time.nanos() + 100_000_000_000_000_000); + let response = execute(deps.as_mut(), env.clone(), info, msg.clone()); + assert!(response.is_ok()); + + let info = mock_info("owner", &[]); + let response = execute(deps.as_mut(), env.clone(), info, msg.clone()); + assert!(response.is_err()); + } + + #[test] + fn test_staking_account() { + let mut deps = init_contract(); + let mut env = mock_env(); + let info = mock_info("staking", &[]); + let msg = ExecuteMsg::TransferOwnership { + to_address: "new_owner".to_string(), + }; + let response = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()); + // Only owner can transfer + assert!(response.is_err()); + + let msg = ExecuteMsg::WithdrawVestedCoins { + amount: Coin { + amount: Uint128::new(1), + denom: "nym".to_string(), + }, + }; + env.block.time = Timestamp::from_nanos(env.block.time.nanos() + 100_000_000_000_000_000); + let response = execute(deps.as_mut(), env.clone(), info, msg.clone()); + // Only owner can withdraw + assert!(response.is_err()); } #[test] diff --git a/gateway/src/commands/sign.rs b/gateway/src/commands/sign.rs index 1fa8963100..d0e91393bd 100644 --- a/gateway/src/commands/sign.rs +++ b/gateway/src/commands/sign.rs @@ -5,14 +5,9 @@ use crate::commands::*; use crate::config::{persistence::pathfinder::GatewayPathfinder, Config}; use clap::{App, Arg, ArgMatches}; use colored::Colorize; -#[cfg(feature = "coconut")] -use config::defaults::BECH32_PREFIX; use config::NymConfig; use crypto::asymmetric::identity; use log::error; -use std::process; -#[cfg(feature = "coconut")] -use subtle_encoding::bech32; #[cfg(not(feature = "coconut"))] use validator_client::nymd::AccountId; @@ -111,7 +106,7 @@ fn sign_derived_address(private_key: &identity::PrivateKey, address: &AccountId) // we do tiny bit of sanity check validation #[cfg(feature = "coconut")] -fn print_signed_address(private_key: &identity::PrivateKey, raw_address: &str) -> String { +fn sign_provided_address(private_key: &identity::PrivateKey, raw_address: &str) { let trimmed = raw_address.trim(); validate_bech32_address_or_exit(trimmed); let signature = private_key.sign_text(trimmed); @@ -119,8 +114,7 @@ fn print_signed_address(private_key: &identity::PrivateKey, raw_address: &str) - println!( "The base58-encoded signature on '{}' is: {}", trimmed, signature - ); - signature + ) } fn print_signed_text(private_key: &identity::PrivateKey, text: &str) { diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index 1ef0c5f80d..7ab0c36296 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -5188,7 +5188,9 @@ dependencies = [ "config", "cosmwasm-std", "cw-storage-plus", + "getrandom 0.2.3", "mixnet-contract", + "rand 0.8.4", "schemars", "serde", "thiserror", diff --git a/nym-wallet/src-tauri/Cargo.toml b/nym-wallet/src-tauri/Cargo.toml index 60d6f38b13..8b2da3c711 100644 --- a/nym-wallet/src-tauri/Cargo.toml +++ b/nym-wallet/src-tauri/Cargo.toml @@ -30,7 +30,7 @@ eyre = "0.6.5" cosmrs = { git = "https://github.com/cosmos/cosmos-rust", rev="e5a1872083abb3d88fa62dda966e7f5408deba58", features = ["rpc", "bip32", "cosmwasm"] } -cosmwasm-std = "1.0.0-beta2" +cosmwasm-std = "1.0.0-beta3" validator-client = { path = "../../common/client-libs/validator-client", features = [ "nymd-client",