Skip to content

Commit

Permalink
cosmwasm: updated cw_wormhole state management library
Browse files Browse the repository at this point in the history
  • Loading branch information
kakucodes committed Feb 4, 2025
1 parent daedbab commit ec97f98
Show file tree
Hide file tree
Showing 14 changed files with 49 additions and 94 deletions.
2 changes: 1 addition & 1 deletion cosmwasm/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions cosmwasm/contracts/wormhole-ibc/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use cw_wormhole::{
execute as core_execute, instantiate as core_instantiate, migrate as core_migrate,
query as core_query, query_parse_and_verify_vaa,
},
state::config_read,
state::CONFIG,
};
use wormhole_sdk::{
ibc_receiver::{Action, GovernancePacket},
Expand Down Expand Up @@ -87,8 +87,8 @@ fn handle_vaa(deps: DepsMut, env: Env, vaa: Binary) -> anyhow::Result<Event> {
.context("failed to parse governance packet")?;

// validate the governance VAA is directed to this chain
let state = config_read(deps.storage)
.load()
let state = CONFIG
.load(deps.storage)
.context("failed to load contract config")?;
ensure!(
govpacket.chain == Chain::from(state.chain_id),
Expand Down
2 changes: 1 addition & 1 deletion cosmwasm/contracts/wormhole/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ default = ["full"]

[dependencies]
cosmwasm-std = { version = "1.0.0" }
cosmwasm-storage = { version = "1.0.0" }
cw-storage-plus = { version = "0.13.2" }
cosmwasm-schema = { version = "1.0.0" }
schemars = "0.8.8"
serde = { version = "1.0.137", default-features = false, features = ["derive"] }
Expand Down
45 changes: 24 additions & 21 deletions cosmwasm/contracts/wormhole/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ use crate::{
InstantiateMsg, MigrateMsg, QueryMsg,
},
state::{
config, config_read, guardian_set_get, guardian_set_set, sequence_read, sequence_set,
vaa_archive_add, vaa_archive_check, ConfigInfo, ContractUpgrade, GovernancePacket,
GuardianAddress, GuardianSetInfo, GuardianSetUpgrade, ParsedVAA, SetFee, TransferFee,
guardian_set_get, guardian_set_set, vaa_archive_add, vaa_archive_check, ConfigInfo,
ContractUpgrade, GovernancePacket, GuardianAddress, GuardianSetInfo, GuardianSetUpgrade,
ParsedVAA, SetFee, TransferFee, CONFIG, SEQUENCE,
},
};

Expand Down Expand Up @@ -74,7 +74,7 @@ pub fn instantiate(
chain_id: msg.chain_id,
fee_denom: msg.fee_denom,
};
config(deps.storage).save(&state)?;
CONFIG.save(deps.storage, &state)?;

// Add initial guardian set to storage
guardian_set_set(
Expand Down Expand Up @@ -109,7 +109,7 @@ fn handle_submit_vaa(
_info: MessageInfo,
data: &[u8],
) -> StdResult<Response> {
let state = config_read(deps.storage).load()?;
let state = CONFIG.load(deps.storage)?;

let vaa = parse_and_verify_vaa(deps.storage, data, env.block.time.seconds())?;
vaa_archive_add(deps.storage, vaa.hash.as_slice())?;
Expand All @@ -128,7 +128,7 @@ fn handle_submit_vaa(

fn handle_governance_payload(deps: DepsMut, env: Env, data: &[u8]) -> StdResult<Response> {
let gov_packet = GovernancePacket::deserialize(data)?;
let state = config_read(deps.storage).load()?;
let state = CONFIG.load(deps.storage)?;

let module = String::from_utf8(gov_packet.module).unwrap();
let module: String = module.chars().filter(|c| c != &'\0').collect();
Expand Down Expand Up @@ -232,7 +232,7 @@ fn vaa_update_guardian_set(deps: DepsMut, env: Env, data: &[u8]) -> StdResult<Re
5 [][20]uint8 guardian addresses
*/

let mut state = config_read(deps.storage).load()?;
let mut state = CONFIG.load(deps.storage)?;

let GuardianSetUpgrade {
new_guardian_set_index,
Expand All @@ -249,7 +249,7 @@ fn vaa_update_guardian_set(deps: DepsMut, env: Env, data: &[u8]) -> StdResult<Re

guardian_set_set(deps.storage, state.guardian_set_index, &new_guardian_set)?;

config(deps.storage).save(&state)?;
CONFIG.save(deps.storage, &state)?;

let mut old_guardian_set = guardian_set_get(deps.storage, old_guardian_set_index)?;
old_guardian_set.expiration_time = env.block.time.seconds() + state.guardian_set_expirity;
Expand Down Expand Up @@ -278,12 +278,12 @@ fn vaa_update_contract(_deps: DepsMut, env: Env, data: &[u8]) -> StdResult<Respo
}

pub fn handle_set_fee(deps: DepsMut, _env: Env, data: &[u8]) -> StdResult<Response> {
let mut state = config_read(deps.storage).load()?;
let set_fee_msg = SetFee::deserialize(data, state.fee_denom.clone())?;

// Save new fees
state.fee = set_fee_msg.fee;
config(deps.storage).save(&state)?;
let state = CONFIG.update(deps.storage, |mut state| {
let set_fee_msg = SetFee::deserialize(data, state.fee_denom.clone())?;
// Save new fees
state.fee = set_fee_msg.fee;
Ok::<ConfigInfo, StdError>(state)
})?;

Ok(Response::new()
.add_attribute("action", "fee_change")
Expand All @@ -292,7 +292,7 @@ pub fn handle_set_fee(deps: DepsMut, _env: Env, data: &[u8]) -> StdResult<Respon
}

pub fn handle_transfer_fee(deps: DepsMut, _env: Env, data: &[u8]) -> StdResult<Response> {
let state = config_read(deps.storage).load()?;
let state = CONFIG.load(deps.storage)?;

let transfer_msg = TransferFee::deserialize(data, state.fee_denom)?;

Expand All @@ -310,7 +310,7 @@ fn handle_post_message(
message: &[u8],
nonce: u32,
) -> StdResult<Response> {
let state = config_read(deps.storage).load()?;
let state = CONFIG.load(deps.storage)?;
let fee = state.fee;

// Check fee
Expand All @@ -319,15 +319,18 @@ fn handle_post_message(
}

let emitter = extend_address_to_32(&deps.api.addr_canonicalize(info.sender.as_str())?);
let sequence = sequence_read(deps.storage, emitter.as_slice());
sequence_set(deps.storage, emitter.as_slice(), sequence + 1)?;
let sequence = SEQUENCE.update(deps.storage, emitter.as_slice(), |seq| {
seq.map(|seq| seq + 1).ok_or(StdError::generic_err(
"Sequence not found - handle post message",
))
})?;

Ok(Response::new()
.add_attribute("message.message", hex::encode(message))
.add_attribute("message.sender", hex::encode(emitter))
.add_attribute("message.chain_id", state.chain_id.to_string())
.add_attribute("message.nonce", nonce.to_string())
.add_attribute("message.sequence", sequence.to_string())
.add_attribute("message.sequence", (sequence - 1).to_string())
.add_attribute("message.block_time", env.block.time.seconds().to_string()))
}

Expand All @@ -346,7 +349,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
}

pub fn query_guardian_set_info(deps: Deps) -> StdResult<GuardianSetInfoResponse> {
let state = config_read(deps.storage).load()?;
let state = CONFIG.load(deps.storage)?;
let guardian_set = guardian_set_get(deps.storage, state.guardian_set_index)?;
let res = GuardianSetInfoResponse {
guardian_set_index: state.guardian_set_index,
Expand All @@ -371,7 +374,7 @@ pub fn query_address_hex(deps: Deps, address: &HumanAddr) -> StdResult<GetAddres
}

pub fn query_state(deps: Deps) -> StdResult<GetStateResponse> {
let state = config_read(deps.storage).load()?;
let state = CONFIG.load(deps.storage)?;
let res = GetStateResponse { fee: state.fee };
Ok(res)
}
Expand Down
3 changes: 3 additions & 0 deletions cosmwasm/contracts/wormhole/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ pub enum ContractError {
/// Registering asset outside of the wormhole
#[error("RegistrationForbidden")]
RegistrationForbidden,

#[error("SequenceNotFound")]
SequenceNotFound,
}

impl ContractError {
Expand Down
68 changes: 12 additions & 56 deletions cosmwasm/contracts/wormhole/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
use cosmwasm_std::{Binary, CanonicalAddr, Coin, StdResult, Storage, Uint128};
use cw_storage_plus::{Item, Map};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use cosmwasm_std::{Binary, CanonicalAddr, Coin, StdResult, Storage, Uint128};
use cosmwasm_storage::{
bucket, bucket_read, singleton, singleton_read, Bucket, ReadonlyBucket, ReadonlySingleton,
Singleton,
};

use crate::{byte_utils::ByteUtils, error::ContractError};

use sha3::{Digest, Keccak256};

type HumanAddr = String;

pub static CONFIG_KEY: &[u8] = b"config";
pub static GUARDIAN_SET_KEY: &[u8] = b"guardian_set";
pub static SEQUENCE_KEY: &[u8] = b"sequence";
pub static WRAPPED_ASSET_KEY: &[u8] = b"wrapped_asset";
pub static WRAPPED_ASSET_ADDRESS_KEY: &[u8] = b"wrapped_asset_address";
pub const CONFIG: Item<ConfigInfo> = Item::new("config");
pub const GUARDIAN_SET: Map<u32, GuardianSetInfo> = Map::new("guardian_set");
pub const SEQUENCE: Map<&[u8], u64> = Map::new("sequence");
pub const VAA_ARCHIVE: Map<&[u8], bool> = Map::new("vaa_archive");

/// Legacy version of [`ConfigInfo`]. Required for the migration. In
/// particular, the last two fields of [`ConfigInfo`] have been added after the
Expand Down Expand Up @@ -227,66 +220,29 @@ pub struct WormholeInfo {
pub guardian_set_expirity: u64,
}

pub fn config(storage: &mut dyn Storage) -> Singleton<ConfigInfo> {
singleton(storage, CONFIG_KEY)
}

pub fn config_read(storage: &dyn Storage) -> ReadonlySingleton<ConfigInfo> {
singleton_read(storage, CONFIG_KEY)
}

pub fn config_read_legacy(storage: &dyn Storage) -> ReadonlySingleton<ConfigInfoLegacy> {
singleton_read(storage, CONFIG_KEY)
}

pub fn guardian_set_set(
storage: &mut dyn Storage,
index: u32,
data: &GuardianSetInfo,
) -> StdResult<()> {
bucket(storage, GUARDIAN_SET_KEY).save(&index.to_be_bytes(), data)
GUARDIAN_SET.save(storage, index, data)
}

pub fn guardian_set_get(storage: &dyn Storage, index: u32) -> StdResult<GuardianSetInfo> {
bucket_read(storage, GUARDIAN_SET_KEY).load(&index.to_be_bytes())
}

pub fn sequence_set(storage: &mut dyn Storage, emitter: &[u8], sequence: u64) -> StdResult<()> {
bucket(storage, SEQUENCE_KEY).save(emitter, &sequence)
}

pub fn sequence_read(storage: &dyn Storage, emitter: &[u8]) -> u64 {
bucket_read(storage, SEQUENCE_KEY)
.load(emitter)
.unwrap_or(0)
GUARDIAN_SET.load(storage, index)
}

pub fn vaa_archive_add(storage: &mut dyn Storage, hash: &[u8]) -> StdResult<()> {
bucket(storage, GUARDIAN_SET_KEY).save(hash, &true)
VAA_ARCHIVE.save(storage, hash, &true)
}

pub fn vaa_archive_check(storage: &dyn Storage, hash: &[u8]) -> bool {
bucket_read(storage, GUARDIAN_SET_KEY)
.load(hash)
VAA_ARCHIVE
.may_load(storage, hash)
.unwrap_or(Some(false))
.unwrap_or(false)
}

pub fn wrapped_asset(storage: &mut dyn Storage) -> Bucket<HumanAddr> {
bucket(storage, WRAPPED_ASSET_KEY)
}

pub fn wrapped_asset_read(storage: &dyn Storage) -> ReadonlyBucket<HumanAddr> {
bucket_read(storage, WRAPPED_ASSET_KEY)
}

pub fn wrapped_asset_address(storage: &mut dyn Storage) -> Bucket<Vec<u8>> {
bucket(storage, WRAPPED_ASSET_ADDRESS_KEY)
}

pub fn wrapped_asset_address_read(storage: &dyn Storage) -> ReadonlyBucket<Vec<u8>> {
bucket_read(storage, WRAPPED_ASSET_ADDRESS_KEY)
}

pub struct GovernancePacket {
pub module: Vec<u8>,
pub action: u8,
Expand Down
17 changes: 5 additions & 12 deletions cosmwasm/contracts/wormhole/src/testing/integration.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
use crate::msg::{ExecuteMsg, GetStateResponse, GuardianSetInfoResponse};
use crate::state::CONFIG;
use crate::testing::utils::{
create_transfer_vaa_body, instantiate_with_guardians, sign_vaa_body_version_2,
IntoGuardianAddress, WormholeApp,
};
use crate::{
contract::instantiate,
msg::QueryMsg,
state::{ConfigInfo, GuardianAddress, ParsedVAA, CONFIG_KEY},
state::{ConfigInfo, GuardianAddress, ParsedVAA},
};
use cosmwasm_std::{
from_slice,
testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier, MockStorage},
Coin, OwnedDeps, Response, StdResult, Storage,
Coin, Deps, DepsMut, Empty, OwnedDeps, QuerierWrapper, Response, StdError, StdResult, Uint128,
Uint256,
};
use cosmwasm_std::{Deps, DepsMut, Empty, QuerierWrapper, StdError, Uint128, Uint256};
use cosmwasm_storage::to_length_prefixed;
use cw_multi_test::{ContractWrapper, Executor};
use k256::ecdsa::SigningKey;
use serde_wormhole::RawMessage;
Expand All @@ -26,12 +25,6 @@ use wormhole_sdk::{relayer, Address, Amount, Chain, GuardianSetInfo, GOVERNANCE_

static INITIALIZER: &str = "initializer";

fn get_config_info<S: Storage>(storage: &S) -> ConfigInfo {
let key = to_length_prefixed(CONFIG_KEY);
let data = storage.get(&key).expect("data should exist");
from_slice(&data).expect("invalid data")
}

fn do_init(guardians: &[GuardianAddress]) -> OwnedDeps<MockStorage, MockApi, MockQuerier> {
let mut deps = mock_dependencies();
let init_msg = instantiate_with_guardians(guardians);
Expand All @@ -42,7 +35,7 @@ fn do_init(guardians: &[GuardianAddress]) -> OwnedDeps<MockStorage, MockApi, Moc

// query the store directly
assert_eq!(
get_config_info(&deps.storage),
CONFIG.load(&deps.storage).expect("failed to load config"),
ConfigInfo {
guardian_set_index: 0,
guardian_set_expirity: 50,
Expand Down
Binary file modified wormchain/interchaintest/contracts/cw20_wrapped_2.wasm
Binary file not shown.
Binary file modified wormchain/interchaintest/contracts/cw_wormhole.wasm
Binary file not shown.
Binary file modified wormchain/interchaintest/contracts/ibc_translator.wasm
Binary file not shown.
Binary file modified wormchain/interchaintest/contracts/shutdown_token_bridge.wasm
Binary file not shown.
Binary file modified wormchain/interchaintest/contracts/shutdown_wormhole_core.wasm
Binary file not shown.
Binary file modified wormchain/interchaintest/contracts/token_bridge.wasm
Binary file not shown.
Binary file modified wormchain/interchaintest/contracts/wormhole_ibc.wasm
Binary file not shown.

0 comments on commit ec97f98

Please sign in to comment.