diff --git a/contracts/tgrade-valset/src/contract.rs b/contracts/tgrade-valset/src/contract.rs index a7e1e92a..f5d5b5f2 100644 --- a/contracts/tgrade-valset/src/contract.rs +++ b/contracts/tgrade-valset/src/contract.rs @@ -91,6 +91,7 @@ pub fn instantiate( for op in msg.initial_keys.into_iter() { let oper = deps.api.addr_validate(&op.operator)?; let pubkey: Ed25519Pubkey = op.validator_pubkey.try_into()?; + op.metadata.validate()?; let info = OperatorInfo { pubkey, metadata: op.metadata, @@ -205,6 +206,8 @@ fn execute_register_validator_key( pubkey: Pubkey, metadata: ValidatorMetadata, ) -> Result { + metadata.validate()?; + let pubkey: Ed25519Pubkey = pubkey.try_into()?; let moniker = metadata.moniker.clone(); diff --git a/contracts/tgrade-valset/src/error.rs b/contracts/tgrade-valset/src/error.rs index 1624bfea..aaa2cf39 100644 --- a/contracts/tgrade-valset/src/error.rs +++ b/contracts/tgrade-valset/src/error.rs @@ -36,9 +36,6 @@ pub enum ContractError { #[error("Scaling must be unset or greater than zero")] InvalidScaling {}, - #[error("The moniker field must not be empty")] - InvalidMoniker {}, - #[error("Tendermint pubkey must be 32 bytes long")] InvalidPubkey {}, @@ -71,6 +68,16 @@ pub enum ContractError { #[error("Jail did not yet expire")] JailDidNotExpire {}, + + #[error("Invalid metadata - {data} length must be {min}-{max} characters")] + InvalidMetadata { + data: &'static str, + min: usize, + max: usize, + }, + + #[error("Invalid metadata - website needs to start with http:// or https://")] + InvalidMetadataWebsitePrefix {}, } impl From for ContractError { diff --git a/contracts/tgrade-valset/src/msg.rs b/contracts/tgrade-valset/src/msg.rs index 01082336..0f9bcbab 100644 --- a/contracts/tgrade-valset/src/msg.rs +++ b/contracts/tgrade-valset/src/msg.rs @@ -92,60 +92,6 @@ pub struct InstantiateMsg { pub rewards_code_id: u64, } -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] -pub struct UnvalidatedDistributionContract { - /// The unvalidated address of the contract to which part of the reward tokens is sent to. - pub contract: String, - /// The ratio of total reward tokens for an epoch to be sent to that contract for further - /// distribution. - pub ratio: Decimal, -} - -impl UnvalidatedDistributionContract { - fn validate(self, api: &dyn Api) -> Result { - Ok(DistributionContract { - contract: api.addr_validate(&self.contract)?, - ratio: self.ratio, - }) - } -} - -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] -#[serde(transparent)] -pub struct UnvalidatedDistributionContracts { - pub inner: Vec, -} - -impl UnvalidatedDistributionContracts { - /// Validates the addresses and the sum of ratios. - pub fn validate(self, api: &dyn Api) -> Result, ContractError> { - if self.sum_ratios() > Decimal::one() { - return Err(ContractError::InvalidRewardsRatio {}); - } - - self.inner.into_iter().map(|c| c.validate(api)).collect() - } - - fn sum_ratios(&self) -> Decimal { - self.inner - .iter() - .map(|c| c.ratio) - .fold(Decimal::zero(), Decimal::add) - } -} - -pub fn default_fee_percentage() -> Decimal { - Decimal::zero() -} - -pub fn default_validators_reward_ratio() -> Decimal { - Decimal::one() -} - -pub fn default_double_sign_slash() -> Decimal { - Decimal::percent(50) -} - impl InstantiateMsg { pub fn validate(&self) -> Result<(), ContractError> { if self.epoch_length == 0 { @@ -171,54 +117,6 @@ impl InstantiateMsg { } } -/// Validator Metadata modeled after the Cosmos SDK staking module -#[derive( - Serialize, Deserialize, Clone, Eq, PartialEq, Ord, PartialOrd, JsonSchema, Debug, Default, -)] -pub struct ValidatorMetadata { - /// The validator's name (required) - pub moniker: String, - - /// The optional identity signature (ex. UPort or Keybase) - pub identity: Option, - - /// The validator's (optional) website - pub website: Option, - - /// The validator's (optional) security contact email - pub security_contact: Option, - - /// The validator's (optional) details - pub details: Option, -} - -const MIN_MONIKER_LENGTH: usize = 3; - -impl ValidatorMetadata { - pub fn validate(&self) -> Result<(), ContractError> { - if self.moniker.len() < MIN_MONIKER_LENGTH { - return Err(ContractError::InvalidMoniker {}); - } - Ok(()) - } -} - -/// Maps an sdk address to a Tendermint pubkey. -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] -pub struct OperatorInitInfo { - pub operator: String, - /// TODO: better name to specify this is the Tendermint pubkey for consensus? - pub validator_pubkey: Pubkey, - pub metadata: ValidatorMetadata, -} - -impl OperatorInitInfo { - pub fn validate(&self) -> Result<(), ContractError> { - Ed25519Pubkey::try_from(&self.validator_pubkey)?; - self.metadata.validate() - } -} - #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] #[serde(rename_all = "snake_case")] pub enum ExecuteMsg { @@ -306,6 +204,152 @@ pub enum QueryMsg { Admin {}, } +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +pub struct UnvalidatedDistributionContract { + /// The unvalidated address of the contract to which part of the reward tokens is sent to. + pub contract: String, + /// The ratio of total reward tokens for an epoch to be sent to that contract for further + /// distribution. + pub ratio: Decimal, +} + +impl UnvalidatedDistributionContract { + fn validate(self, api: &dyn Api) -> Result { + Ok(DistributionContract { + contract: api.addr_validate(&self.contract)?, + ratio: self.ratio, + }) + } +} + +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] +#[serde(transparent)] +pub struct UnvalidatedDistributionContracts { + pub inner: Vec, +} + +impl UnvalidatedDistributionContracts { + /// Validates the addresses and the sum of ratios. + pub fn validate(self, api: &dyn Api) -> Result, ContractError> { + if self.sum_ratios() > Decimal::one() { + return Err(ContractError::InvalidRewardsRatio {}); + } + + self.inner.into_iter().map(|c| c.validate(api)).collect() + } + + fn sum_ratios(&self) -> Decimal { + self.inner + .iter() + .map(|c| c.ratio) + .fold(Decimal::zero(), Decimal::add) + } +} + +pub fn default_fee_percentage() -> Decimal { + Decimal::zero() +} + +pub fn default_validators_reward_ratio() -> Decimal { + Decimal::one() +} + +pub fn default_double_sign_slash() -> Decimal { + Decimal::percent(50) +} + +/// Validator Metadata modeled after the Cosmos SDK staking module +#[derive( + Serialize, Deserialize, Clone, Eq, PartialEq, Ord, PartialOrd, JsonSchema, Debug, Default, +)] +pub struct ValidatorMetadata { + /// The validator's name (required) + pub moniker: String, + + /// The optional identity signature (ex. UPort or Keybase) + pub identity: Option, + + /// The validator's (optional) website + pub website: Option, + + /// The validator's (optional) security contact email + pub security_contact: Option, + + /// The validator's (optional) details + pub details: Option, +} + +pub const MIN_MONIKER_LENGTH: usize = 3; +pub const MIN_METADATA_SIZE: usize = 1; +pub const MAX_METADATA_SIZE: usize = 256; + +impl ValidatorMetadata { + pub fn validate(&self) -> Result<(), ContractError> { + if self.moniker.len() < MIN_MONIKER_LENGTH || self.moniker.len() > MAX_METADATA_SIZE { + return Err(ContractError::InvalidMetadata { + data: "moniker", + min: MIN_MONIKER_LENGTH, + max: MAX_METADATA_SIZE, + }); + } + if let Some(identity) = &self.identity { + if identity.is_empty() || identity.len() > MAX_METADATA_SIZE { + return Err(ContractError::InvalidMetadata { + data: "identity", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE, + }); + } + } + if let Some(website) = &self.website { + if website.is_empty() || website.len() > MAX_METADATA_SIZE { + return Err(ContractError::InvalidMetadata { + data: "website", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE, + }); + } else if !website.starts_with("https://") && !website.starts_with("http://") { + return Err(ContractError::InvalidMetadataWebsitePrefix {}); + } + } + if let Some(security_contract) = &self.security_contact { + if security_contract.is_empty() || security_contract.len() > MAX_METADATA_SIZE { + return Err(ContractError::InvalidMetadata { + data: "security_contract", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE, + }); + } + } + if let Some(details) = &self.details { + if details.is_empty() || details.len() > MAX_METADATA_SIZE { + return Err(ContractError::InvalidMetadata { + data: "details", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE, + }); + } + } + Ok(()) + } +} + +/// Maps an sdk address to a Tendermint pubkey. +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +pub struct OperatorInitInfo { + pub operator: String, + /// TODO: better name to specify this is the Tendermint pubkey for consensus? + pub validator_pubkey: Pubkey, + pub metadata: ValidatorMetadata, +} + +impl OperatorInitInfo { + pub fn validate(&self) -> Result<(), ContractError> { + Ed25519Pubkey::try_from(&self.validator_pubkey)?; + self.metadata.validate() + } +} + #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct EpochResponse { /// Number of seconds in one epoch. We update the Tendermint validator set only once per epoch. @@ -518,4 +562,132 @@ mod test { let err = invalid.validate().unwrap_err(); assert_eq!(err, ContractError::InvalidRewardDenom {}); } + + #[test] + fn validate_metadata() { + let meta = ValidatorMetadata { + moniker: "example".to_owned(), + identity: Some((0..MAX_METADATA_SIZE + 1).map(|_| "X").collect::()), + website: Some((0..MAX_METADATA_SIZE + 1).map(|_| "X").collect::()), + security_contact: Some((0..MAX_METADATA_SIZE + 1).map(|_| "X").collect::()), + details: Some((0..MAX_METADATA_SIZE + 1).map(|_| "X").collect::()), + }; + let resp = meta.validate().unwrap_err(); + assert_eq!( + ContractError::InvalidMetadata { + data: "identity", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE + }, + resp + ); + + let meta = ValidatorMetadata { + identity: Some("identity".to_owned()), + ..meta + }; + let resp = meta.validate().unwrap_err(); + assert_eq!( + ContractError::InvalidMetadata { + data: "website", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE, + }, + resp + ); + + let meta = ValidatorMetadata { + website: Some("https://website".to_owned()), + ..meta + }; + let resp = meta.validate().unwrap_err(); + assert_eq!( + ContractError::InvalidMetadata { + data: "security_contract", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE, + }, + resp + ); + + let meta = ValidatorMetadata { + security_contact: Some("contract".to_owned()), + ..meta + }; + let resp = meta.validate().unwrap_err(); + assert_eq!( + ContractError::InvalidMetadata { + data: "details", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE, + }, + resp + ); + + let meta = ValidatorMetadata { + identity: Some(String::new()), + website: Some(String::new()), + security_contact: Some(String::new()), + details: Some(String::new()), + ..meta + }; + let resp = meta.validate().unwrap_err(); + assert_eq!( + ContractError::InvalidMetadata { + data: "identity", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE + }, + resp + ); + + let meta = ValidatorMetadata { + identity: Some("identity".to_owned()), + ..meta + }; + let resp = meta.validate().unwrap_err(); + assert_eq!( + ContractError::InvalidMetadata { + data: "website", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE, + }, + resp + ); + + let meta = ValidatorMetadata { + website: Some("http://website".to_owned()), + ..meta + }; + let resp = meta.validate().unwrap_err(); + assert_eq!( + ContractError::InvalidMetadata { + data: "security_contract", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE, + }, + resp + ); + + let meta = ValidatorMetadata { + security_contact: Some("contract".to_owned()), + ..meta + }; + let resp = meta.validate().unwrap_err(); + assert_eq!( + ContractError::InvalidMetadata { + data: "details", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE, + }, + resp + ); + + let meta = ValidatorMetadata { + website: Some("website".to_owned()), + ..meta + }; + let resp = meta.validate().unwrap_err(); + assert_eq!(ContractError::InvalidMetadataWebsitePrefix {}, resp); + } } diff --git a/contracts/tgrade-valset/src/multitest/contract.rs b/contracts/tgrade-valset/src/multitest/contract.rs index 98ce8901..70d1c702 100644 --- a/contracts/tgrade-valset/src/multitest/contract.rs +++ b/contracts/tgrade-valset/src/multitest/contract.rs @@ -1,8 +1,10 @@ use crate::error::ContractError; -use crate::msg::{EpochResponse, ValidatorMetadata}; +use crate::msg::{ + EpochResponse, ValidatorMetadata, MAX_METADATA_SIZE, MIN_METADATA_SIZE, MIN_MONIKER_LENGTH, +}; use crate::state::Config; -use super::helpers::{assert_active_validators, assert_operators, members_init}; +use super::helpers::{addr_to_pubkey, assert_active_validators, assert_operators, members_init}; use super::suite::SuiteBuilder; use assert_matches::assert_matches; use cosmwasm_std::{coin, Decimal}; @@ -174,7 +176,14 @@ fn update_metadata() { let resp = suite .update_metadata(members[0], &invalid_meta) .unwrap_err(); - assert_eq!(ContractError::InvalidMoniker {}, resp.downcast().unwrap()); + assert_eq!( + ContractError::InvalidMetadata { + data: "moniker", + min: MIN_MONIKER_LENGTH, + max: MAX_METADATA_SIZE, + }, + resp.downcast().unwrap() + ); // Ensure no metadata changed let resp = suite.validator(members[0]).unwrap(); @@ -260,3 +269,179 @@ fn list_validators_paginated() { ], ); } + +#[test] +fn register_key_invalid_metadata() { + let members = vec!["member1"]; + + let mut suite = SuiteBuilder::new() + .with_engagement(&members_init(&members, &[2, 3, 5, 8, 13, 21])) + .with_operators(&members) + .with_min_points(5) + .build(); + + let meta = ValidatorMetadata { + moniker: "example".to_owned(), + identity: Some((0..MAX_METADATA_SIZE + 1).map(|_| "X").collect::()), + website: Some((0..MAX_METADATA_SIZE + 1).map(|_| "X").collect::()), + security_contact: Some((0..MAX_METADATA_SIZE + 1).map(|_| "X").collect::()), + details: Some((0..MAX_METADATA_SIZE + 1).map(|_| "X").collect::()), + }; + let pubkey = addr_to_pubkey(members[0]); + let resp = suite + .register_validator_key(members[0], pubkey.clone(), meta.clone()) + .unwrap_err(); + assert_eq!( + ContractError::InvalidMetadata { + data: "identity", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE + }, + resp.downcast().unwrap() + ); + + let meta = ValidatorMetadata { + identity: Some(String::new()), + website: Some(String::new()), + security_contact: Some(String::new()), + details: Some(String::new()), + ..meta + }; + let resp = suite + .register_validator_key(members[0], pubkey, meta) + .unwrap_err(); + assert_eq!( + ContractError::InvalidMetadata { + data: "identity", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE + }, + resp.downcast().unwrap() + ); +} + +#[test] +fn update_metadata_invalid_metadata() { + let members = vec!["member1"]; + + let mut suite = SuiteBuilder::new() + .with_engagement(&members_init(&members, &[2, 3, 5, 8, 13, 21])) + .with_operators(&members) + .with_min_points(5) + .build(); + + let meta = ValidatorMetadata { + moniker: "example".to_owned(), + identity: Some((0..MAX_METADATA_SIZE + 1).map(|_| "X").collect::()), + website: Some((0..MAX_METADATA_SIZE + 1).map(|_| "X").collect::()), + security_contact: Some((0..MAX_METADATA_SIZE + 1).map(|_| "X").collect::()), + details: Some((0..MAX_METADATA_SIZE + 1).map(|_| "X").collect::()), + }; + let resp = suite.update_metadata(members[0], &meta).unwrap_err(); + assert_eq!( + ContractError::InvalidMetadata { + data: "identity", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE + }, + resp.downcast().unwrap() + ); + + let meta = ValidatorMetadata { + identity: Some(String::new()), + website: Some(String::new()), + security_contact: Some(String::new()), + details: Some(String::new()), + ..meta + }; + let resp = suite.update_metadata(members[0], &meta).unwrap_err(); + assert_eq!( + ContractError::InvalidMetadata { + data: "identity", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE + }, + resp.downcast().unwrap() + ); +} + +mod instantiate { + use cosmwasm_std::{coin, Addr, Decimal, Uint128}; + use cw_multi_test::{AppBuilder, BasicApp, Executor}; + use tg_bindings::TgradeMsg; + + use crate::error::ContractError; + use crate::msg::{ + InstantiateMsg, OperatorInitInfo, UnvalidatedDistributionContracts, ValidatorMetadata, + MAX_METADATA_SIZE, MIN_METADATA_SIZE, + }; + use crate::multitest::suite::{contract_stake, contract_valset}; + use crate::test_helpers::mock_pubkey; + + #[test] + fn instantiate_invalid_metadata() { + let mut app: BasicApp = AppBuilder::new_custom().build(|_, _, _| ()); + + let stake_id = app.store_code(contract_stake()); + let admin = "steakhouse owner".to_owned(); + let msg = tg4_stake::msg::InstantiateMsg { + denom: "james bond denom".to_owned(), + tokens_per_point: Uint128::new(10), + min_bond: Uint128::new(1), + unbonding_period: 1234, + admin: Some(admin.clone()), + preauths_hooks: 0, + preauths_slashing: 1, + auto_return_limit: 0, + }; + let stake_addr = app + .instantiate_contract( + stake_id, + Addr::unchecked(admin.clone()), + &msg, + &[], + "stake", + Some(admin.clone()), + ) + .unwrap(); + + let valset_id = app.store_code(contract_valset()); + + let member = OperatorInitInfo { + operator: "example".to_owned(), + validator_pubkey: mock_pubkey("example".as_bytes()), + metadata: ValidatorMetadata { + moniker: "example".into(), + details: Some(String::new()), // <- invalid (empty) details field in metadata + ..ValidatorMetadata::default() + }, + }; + let msg = InstantiateMsg { + admin: None, + membership: stake_addr.into(), + min_points: 1, + max_validators: 120, + epoch_length: 10, + epoch_reward: coin(1, "denom"), + initial_keys: [member].to_vec(), + scaling: None, + fee_percentage: Decimal::zero(), + auto_unjail: false, + double_sign_slash_ratio: Decimal::percent(50), + distribution_contracts: UnvalidatedDistributionContracts::default(), + rewards_code_id: 1, + }; + + let err = app + .instantiate_contract(valset_id, Addr::unchecked(admin), &msg, &[], "valset", None) + .unwrap_err(); + assert_eq!( + ContractError::InvalidMetadata { + data: "details", + min: MIN_METADATA_SIZE, + max: MAX_METADATA_SIZE + }, + err.downcast().unwrap() + ); + } +} diff --git a/contracts/tgrade-valset/src/multitest/double_sign.rs b/contracts/tgrade-valset/src/multitest/double_sign.rs index 611ff793..e8c6205b 100644 --- a/contracts/tgrade-valset/src/multitest/double_sign.rs +++ b/contracts/tgrade-valset/src/multitest/double_sign.rs @@ -2,10 +2,11 @@ use cosmwasm_std::coin; use cosmwasm_std::{Binary, Decimal}; use tg_bindings::{Ed25519Pubkey, Evidence, EvidenceType, ToAddress, Validator}; -use super::helpers::{addr_to_pubkey, assert_operators, mock_pubkey}; +use super::helpers::{addr_to_pubkey, assert_operators}; use super::suite::SuiteBuilder; use crate::msg::{JailingPeriod, ValidatorMetadata}; use crate::multitest::helpers::members_init; +use crate::test_helpers::mock_pubkey; use std::convert::TryFrom; diff --git a/contracts/tgrade-valset/src/multitest/helpers.rs b/contracts/tgrade-valset/src/multitest/helpers.rs index 48235f59..a8b7735b 100644 --- a/contracts/tgrade-valset/src/multitest/helpers.rs +++ b/contracts/tgrade-valset/src/multitest/helpers.rs @@ -1,7 +1,7 @@ use cosmwasm_std::Binary; use tg_bindings::Pubkey; -use crate::msg::{JailingPeriod, OperatorResponse, ValidatorMetadata}; +use crate::msg::{JailingPeriod, OperatorResponse}; use crate::state::ValidatorInfo; // Converts address to valid public key @@ -10,23 +10,6 @@ pub fn addr_to_pubkey(addr: &str) -> Pubkey { Pubkey::Ed25519(Binary((*addr).as_bytes().to_vec())) } -pub fn mock_pubkey(base: &[u8]) -> Pubkey { - const ED25519_PUBKEY_LENGTH: usize = 32; - - let copies = (ED25519_PUBKEY_LENGTH / base.len()) + 1; - let mut raw = base.repeat(copies); - raw.truncate(ED25519_PUBKEY_LENGTH); - Pubkey::Ed25519(Binary(raw)) -} - -pub fn mock_metadata(seed: &str) -> ValidatorMetadata { - ValidatorMetadata { - moniker: seed.into(), - details: Some(format!("I'm really {}", seed)), - ..ValidatorMetadata::default() - } -} - pub fn members_init<'m>(members: &[&'m str], weights: &[u64]) -> Vec<(&'m str, u64)> { members .iter() diff --git a/contracts/tgrade-valset/src/multitest/suite.rs b/contracts/tgrade-valset/src/multitest/suite.rs index 01fa4ab7..2e0c306c 100644 --- a/contracts/tgrade-valset/src/multitest/suite.rs +++ b/contracts/tgrade-valset/src/multitest/suite.rs @@ -1,5 +1,6 @@ -use super::helpers::{addr_to_pubkey, mock_metadata, mock_pubkey}; +use super::helpers::addr_to_pubkey; use crate::state::Config; +use crate::test_helpers::{mock_metadata, mock_pubkey}; use crate::{msg::*, state::ValidatorInfo}; use anyhow::{bail, Result as AnyResult}; use cosmwasm_std::{ @@ -23,7 +24,7 @@ pub fn contract_engagement() -> Box> { Box::new(contract) } -fn contract_stake() -> Box> { +pub fn contract_stake() -> Box> { let contract = ContractWrapper::new( tg4_stake::contract::execute, tg4_stake::contract::instantiate, diff --git a/contracts/tgrade-valset/tests/integration.rs b/contracts/tgrade-valset/tests/integration.rs index d58fa563..19e4cb4a 100644 --- a/contracts/tgrade-valset/tests/integration.rs +++ b/contracts/tgrade-valset/tests/integration.rs @@ -15,6 +15,7 @@ use tg_bindings::Pubkey; use tgrade_valset::msg::ExecuteMsg; use tgrade_valset::state::ValidatorInfo; +use tgrade_valset::test_helpers::mock_pubkey; // Copied from test_helpers // returns a list of addresses that are set in the tg4-stake contract @@ -50,16 +51,6 @@ fn mock_instance_on_tgrade(wasm: &[u8]) -> Instance Pubkey { - let copies = (ED25519_PUBKEY_LENGTH / base.len()) + 1; - let mut raw = base.repeat(copies); - raw.truncate(ED25519_PUBKEY_LENGTH); - Pubkey::Ed25519(Binary(raw)) -} - static WASM: &[u8] = include_bytes!("../../../target/wasm32-unknown-unknown/debug/tgrade_valset.wasm");