switch terra contracts over to using governance packet structure
Change-Id: I10b53cb0cfdb86ca2aa57cab20ec375a26fd252e
This commit is contained in:
parent
08ca466a40
commit
2025efd50a
|
@ -8,7 +8,7 @@ use crate::msg::{HandleMsg, InitMsg, QueryMsg};
|
|||
use crate::state::{
|
||||
bridge_contracts, bridge_contracts_read, config, config_read, wrapped_asset,
|
||||
wrapped_asset_address, wrapped_asset_address_read, wrapped_asset_read, Action, AssetMeta,
|
||||
ConfigInfo, TokenBridgeMessage, TransferInfo,
|
||||
ConfigInfo, RegisterChain, TokenBridgeMessage, TransferInfo,
|
||||
};
|
||||
use wormhole::byte_utils::ByteUtils;
|
||||
use wormhole::byte_utils::{extend_address_to_32, extend_string_to_32};
|
||||
|
@ -20,7 +20,7 @@ use cw20_base::msg::QueryMsg as TokenQuery;
|
|||
use wormhole::msg::HandleMsg as WormholeHandleMsg;
|
||||
use wormhole::msg::QueryMsg as WormholeQueryMsg;
|
||||
|
||||
use wormhole::state::ParsedVAA;
|
||||
use wormhole::state::{GovernancePacket, ParsedVAA};
|
||||
|
||||
use cw20::TokenInfoResponse;
|
||||
|
||||
|
@ -43,7 +43,8 @@ pub fn init<S: Storage, A: Api, Q: Querier>(
|
|||
) -> StdResult<InitResponse> {
|
||||
// Save general wormhole info
|
||||
let state = ConfigInfo {
|
||||
owner: msg.owner,
|
||||
gov_chain: msg.gov_chain,
|
||||
gov_address: msg.gov_address.as_slice().to_vec(),
|
||||
wormhole_contract: msg.wormhole_contract,
|
||||
wrapped_asset_code_id: msg.wrapped_asset_code_id,
|
||||
};
|
||||
|
@ -93,10 +94,6 @@ pub fn handle<S: Storage, A: Api, Q: Querier>(
|
|||
nonce,
|
||||
),
|
||||
HandleMsg::SubmitVaa { data } => submit_vaa(deps, env, &data),
|
||||
HandleMsg::RegisterChain {
|
||||
chain_id,
|
||||
chain_address,
|
||||
} => handle_register_chain(deps, env, chain_id, chain_address.as_slice().to_vec()),
|
||||
HandleMsg::CreateAssetMeta {
|
||||
asset_address,
|
||||
nonce,
|
||||
|
@ -104,38 +101,6 @@ pub fn handle<S: Storage, A: Api, Q: Querier>(
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_register_chain<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
chain_id: u16,
|
||||
chain_address: Vec<u8>,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let cfg = config_read(&deps.storage).load()?;
|
||||
|
||||
if env.message.sender != cfg.owner {
|
||||
return Err(StdError::unauthorized());
|
||||
}
|
||||
|
||||
let existing = bridge_contracts_read(&deps.storage).load(&chain_id.to_be_bytes());
|
||||
if existing.is_ok() {
|
||||
return Err(StdError::generic_err(
|
||||
"bridge contract already exists for this chain",
|
||||
));
|
||||
}
|
||||
|
||||
let mut bucket = bridge_contracts(&mut deps.storage);
|
||||
bucket.save(&chain_id.to_be_bytes(), &chain_address)?;
|
||||
|
||||
Ok(HandleResponse {
|
||||
messages: vec![],
|
||||
log: vec![
|
||||
log("chain_id", chain_id),
|
||||
log("chain_address", hex::encode(chain_address)),
|
||||
],
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Handle wrapped asset registration messages
|
||||
fn handle_register_asset<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
|
@ -269,9 +234,16 @@ fn submit_vaa<S: Storage, A: Api, Q: Querier>(
|
|||
env: Env,
|
||||
data: &Binary,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let state = config_read(&deps.storage).load()?;
|
||||
|
||||
let vaa = parse_vaa(deps, env.block.time, data)?;
|
||||
let data = vaa.payload;
|
||||
|
||||
// check if vaa is from governance
|
||||
if state.gov_chain == vaa.emitter_chain && state.gov_address == vaa.emitter_address {
|
||||
return handle_governance_payload(deps, env, &data);
|
||||
}
|
||||
|
||||
let message = TokenBridgeMessage::deserialize(&data)?;
|
||||
|
||||
let result = match message.action {
|
||||
|
@ -288,6 +260,56 @@ fn submit_vaa<S: Storage, A: Api, Q: Querier>(
|
|||
return result;
|
||||
}
|
||||
|
||||
fn handle_governance_payload<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
data: &Vec<u8>,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let gov_packet = GovernancePacket::deserialize(&data)?;
|
||||
|
||||
let module = String::from_utf8(gov_packet.module).unwrap();
|
||||
let module: String = module.chars().filter(|c| !c.is_whitespace()).collect();
|
||||
|
||||
if module != "token_bridge" {
|
||||
return Err(StdError::generic_err("this is not a valid module"))
|
||||
}
|
||||
|
||||
match gov_packet.action {
|
||||
0u8 => handle_register_chain(deps, env, &gov_packet.payload),
|
||||
_ => ContractError::InvalidVAAAction.std_err(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_register_chain<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
data: &Vec<u8>,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let RegisterChain {
|
||||
chain_id,
|
||||
chain_address,
|
||||
} = RegisterChain::deserialize(&data)?;
|
||||
|
||||
let existing = bridge_contracts_read(&deps.storage).load(&chain_id.to_be_bytes());
|
||||
if existing.is_ok() {
|
||||
return Err(StdError::generic_err(
|
||||
"bridge contract already exists for this chain",
|
||||
));
|
||||
}
|
||||
|
||||
let mut bucket = bridge_contracts(&mut deps.storage);
|
||||
bucket.save(&chain_id.to_be_bytes(), &chain_address)?;
|
||||
|
||||
Ok(HandleResponse {
|
||||
messages: vec![],
|
||||
log: vec![
|
||||
log("chain_id", chain_id),
|
||||
log("chain_address", hex::encode(chain_address)),
|
||||
],
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_complete_transfer<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
|
|
|
@ -4,7 +4,11 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct InitMsg {
|
||||
pub owner: HumanAddr,
|
||||
|
||||
// governance contract details
|
||||
pub gov_chain: u16,
|
||||
pub gov_address: Binary,
|
||||
|
||||
pub wormhole_contract: HumanAddr,
|
||||
pub wrapped_asset_code_id: u64,
|
||||
}
|
||||
|
@ -30,11 +34,6 @@ pub enum HandleMsg {
|
|||
data: Binary,
|
||||
},
|
||||
|
||||
RegisterChain {
|
||||
chain_id: u16,
|
||||
chain_address: Binary,
|
||||
},
|
||||
|
||||
CreateAssetMeta {
|
||||
asset_address: HumanAddr,
|
||||
nonce: u32,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use cosmwasm_std::{HumanAddr, StdResult, Storage};
|
||||
use cosmwasm_std::{HumanAddr, StdResult, Storage, Binary};
|
||||
use cosmwasm_storage::{
|
||||
bucket, bucket_read, singleton, singleton_read, Bucket, ReadonlyBucket, ReadonlySingleton,
|
||||
Singleton,
|
||||
|
@ -18,8 +18,10 @@ pub static BRIDGE_CONTRACTS: &[u8] = b"bridge_contracts";
|
|||
// Guardian set information
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct ConfigInfo {
|
||||
// Current active guardian set
|
||||
pub owner: HumanAddr,
|
||||
// governance contract details
|
||||
pub gov_chain: u16,
|
||||
pub gov_address: Vec<u8>,
|
||||
|
||||
pub wormhole_contract: HumanAddr,
|
||||
pub wrapped_asset_code_id: u64,
|
||||
}
|
||||
|
@ -184,3 +186,23 @@ impl AssetMeta {
|
|||
.concat()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RegisterChain {
|
||||
pub chain_id: u16,
|
||||
pub chain_address: Vec<u8>,
|
||||
}
|
||||
|
||||
impl RegisterChain {
|
||||
|
||||
pub fn deserialize(data: &Vec<u8>) -> StdResult<Self> {
|
||||
let data = data.as_slice();
|
||||
let chain_id = data.get_u16(0);
|
||||
let chain_address = data[2..].to_vec();
|
||||
|
||||
Ok(RegisterChain {
|
||||
chain_id,
|
||||
chain_address
|
||||
})
|
||||
}
|
||||
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
use cosmwasm_std::{
|
||||
has_coins, log, to_binary, Api, BankMsg, Binary, Coin, CosmosMsg, Env, Extern, HandleResponse,
|
||||
HumanAddr, InitResponse, Querier, StdError, StdResult, Storage,
|
||||
WasmMsg
|
||||
};
|
||||
|
||||
use crate::byte_utils::extend_address_to_32;
|
||||
use crate::byte_utils::ByteUtils;
|
||||
use crate::error::ContractError;
|
||||
use crate::msg::{
|
||||
GetAddressHexResponse, GetStateResponse, GuardianSetInfoResponse, HandleMsg, InitMsg, QueryMsg,
|
||||
};
|
||||
use crate::msg::{GetAddressHexResponse, GetStateResponse, GuardianSetInfoResponse, HandleMsg, InitMsg, QueryMsg};
|
||||
use crate::state::{
|
||||
config, config_read, guardian_set_get, guardian_set_set, vaa_archive_add, vaa_archive_check,
|
||||
ConfigInfo, GuardianAddress, GuardianSetInfo, ParsedVAA, WormholeGovernance,
|
||||
ConfigInfo, GovernancePacket, GuardianAddress, GuardianSetInfo, GuardianSetUpgrade, ParsedVAA,
|
||||
TransferFee,
|
||||
};
|
||||
|
||||
use k256::ecdsa::recoverable::Id as RecoverableId;
|
||||
|
@ -22,7 +22,6 @@ use k256::EncodedPoint;
|
|||
use sha3::{Digest, Keccak256};
|
||||
|
||||
use generic_array::GenericArray;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
// Chain ID of Terra
|
||||
|
@ -39,9 +38,10 @@ pub fn init<S: Storage, A: Api, Q: Querier>(
|
|||
) -> StdResult<InitResponse> {
|
||||
// Save general wormhole info
|
||||
let state = ConfigInfo {
|
||||
gov_chain: msg.gov_chain,
|
||||
gov_address: msg.gov_address.as_slice().to_vec(),
|
||||
guardian_set_index: 0,
|
||||
guardian_set_expirity: msg.guardian_set_expirity,
|
||||
owner: deps.api.canonical_address(&env.message.sender)?,
|
||||
fee: Coin::new(FEE_AMOUNT, FEE_DENOMINATION), // 0.01 Luna (or 10000 uluna) fee by default
|
||||
};
|
||||
config(&mut deps.storage).save(&state)?;
|
||||
|
@ -65,10 +65,6 @@ pub fn handle<S: Storage, A: Api, Q: Querier>(
|
|||
HandleMsg::PostMessage { message, nonce } => {
|
||||
handle_post_message(deps, env, &message.as_slice(), nonce)
|
||||
}
|
||||
// HandleMsg::SubmitVAA { vaa } => handle_submit_vaa(deps, env, &vaa.as_slice()),
|
||||
HandleMsg::TransferFee { amount, recipient } => {
|
||||
handle_transfer_fee(deps, env, amount, recipient)
|
||||
}
|
||||
HandleMsg::SubmitVAA { vaa } => handle_submit_vaa(deps, env, vaa.as_slice()),
|
||||
}
|
||||
}
|
||||
|
@ -82,30 +78,33 @@ fn handle_submit_vaa<S: Storage, A: Api, Q: Querier>(
|
|||
let state = config_read(&deps.storage).load()?;
|
||||
|
||||
let vaa = parse_and_verify_vaa(&deps.storage, data, env.block.time)?;
|
||||
if vaa.emitter_chain != 0u16 {
|
||||
// chain 0 is the wormhole chain ?
|
||||
return Err(StdError::generic_err(
|
||||
"governance actions may only come from chain 0",
|
||||
));
|
||||
if state.gov_chain == vaa.emitter_chain && state.gov_address == vaa.emitter_address {
|
||||
return handle_governance_payload(deps, env, &vaa.payload);
|
||||
}
|
||||
|
||||
let gov = WormholeGovernance::deserialize(&vaa.payload)?;
|
||||
ContractError::InvalidVAAAction.std_err()
|
||||
}
|
||||
|
||||
let result = match gov.action {
|
||||
0u8 => {
|
||||
if vaa.guardian_set_index != state.guardian_set_index {
|
||||
return ContractError::NotCurrentGuardianSet.std_err();
|
||||
}
|
||||
vaa_update_guardian_set(deps, env, gov.payload.as_slice())
|
||||
}
|
||||
fn handle_governance_payload<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
data: &Vec<u8>,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let gov_packet = GovernancePacket::deserialize(&data)?;
|
||||
|
||||
let module = String::from_utf8(gov_packet.module).unwrap();
|
||||
let module: String = module.chars().filter(|c| !c.is_whitespace()).collect();
|
||||
|
||||
if module != "core" {
|
||||
return Err(StdError::generic_err("this is not a valid module"))
|
||||
}
|
||||
|
||||
match gov_packet.action {
|
||||
// 0 is reserved for upgrade / migration
|
||||
1u8 => vaa_update_guardian_set(deps, env, &gov_packet.payload),
|
||||
2u8 => handle_transfer_fee(deps, env, &gov_packet.payload),
|
||||
_ => ContractError::InvalidVAAAction.std_err(),
|
||||
};
|
||||
|
||||
if result.is_ok() {
|
||||
vaa_archive_add(&mut deps.storage, vaa.hash.as_slice())?;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Parses raw VAA data into a struct and verifies whether it contains sufficient signatures of an
|
||||
|
@ -182,7 +181,7 @@ fn parse_and_verify_vaa<S: Storage>(
|
|||
fn vaa_update_guardian_set<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
data: &[u8],
|
||||
data: &Vec<u8>,
|
||||
) -> StdResult<HandleResponse> {
|
||||
/* Payload format
|
||||
0 uint32 new_index
|
||||
|
@ -190,41 +189,19 @@ fn vaa_update_guardian_set<S: Storage, A: Api, Q: Querier>(
|
|||
5 [][20]uint8 guardian addresses
|
||||
*/
|
||||
|
||||
const GUARDIAN_INDEX_POS: usize = 0;
|
||||
const LENGTH_POS: usize = 4;
|
||||
const ADDRESS_POS: usize = 5;
|
||||
const ADDRESS_LEN: usize = 20;
|
||||
|
||||
if ADDRESS_POS >= data.len() {
|
||||
return ContractError::InvalidVAA.std_err();
|
||||
}
|
||||
|
||||
let mut state = config_read(&deps.storage).load()?;
|
||||
|
||||
let new_guardian_set_index = data.get_u32(GUARDIAN_INDEX_POS);
|
||||
let GuardianSetUpgrade {
|
||||
new_guardian_set_index,
|
||||
new_guardian_set,
|
||||
} = GuardianSetUpgrade::deserialize(&data)?;
|
||||
|
||||
if new_guardian_set_index != state.guardian_set_index + 1 {
|
||||
return ContractError::GuardianSetIndexIncreaseError.std_err();
|
||||
}
|
||||
let len = data.get_u8(LENGTH_POS);
|
||||
|
||||
let mut new_guardian_set = GuardianSetInfo {
|
||||
addresses: vec![],
|
||||
expiration_time: 0,
|
||||
};
|
||||
let mut pos = ADDRESS_POS;
|
||||
for _ in 0..len {
|
||||
if pos + ADDRESS_LEN > data.len() {
|
||||
return ContractError::InvalidVAA.std_err();
|
||||
}
|
||||
|
||||
new_guardian_set.addresses.push(GuardianAddress {
|
||||
bytes: data[pos..pos + ADDRESS_LEN].to_vec().into(),
|
||||
});
|
||||
pos += ADDRESS_LEN;
|
||||
}
|
||||
|
||||
let old_guardian_set_index = state.guardian_set_index;
|
||||
|
||||
state.guardian_set_index = new_guardian_set_index;
|
||||
|
||||
guardian_set_set(
|
||||
|
@ -232,6 +209,7 @@ fn vaa_update_guardian_set<S: Storage, A: Api, Q: Querier>(
|
|||
state.guardian_set_index,
|
||||
&new_guardian_set,
|
||||
)?;
|
||||
|
||||
config(&mut deps.storage).save(&state)?;
|
||||
|
||||
let mut old_guardian_set = guardian_set_get(&deps.storage, old_guardian_set_index)?;
|
||||
|
@ -249,6 +227,24 @@ fn vaa_update_guardian_set<S: Storage, A: Api, Q: Querier>(
|
|||
})
|
||||
}
|
||||
|
||||
pub fn handle_transfer_fee<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
data: &Vec<u8>,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let transfer_msg = TransferFee::deserialize(&data)?;
|
||||
|
||||
Ok(HandleResponse {
|
||||
messages: vec![CosmosMsg::Bank(BankMsg::Send {
|
||||
from_address: env.contract.address,
|
||||
to_address: deps.api.human_address(&transfer_msg.recipient)?,
|
||||
amount: vec![transfer_msg.amount],
|
||||
})],
|
||||
log: vec![],
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_post_message<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
|
@ -280,29 +276,6 @@ fn handle_post_message<S: Storage, A: Api, Q: Querier>(
|
|||
})
|
||||
}
|
||||
|
||||
pub fn handle_transfer_fee<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
amount: Coin,
|
||||
recipient: HumanAddr,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let state = config_read(&deps.storage).load()?;
|
||||
|
||||
if deps.api.canonical_address(&env.message.sender)? != state.owner {
|
||||
return ContractError::PermissionDenied.std_err();
|
||||
}
|
||||
|
||||
Ok(HandleResponse {
|
||||
messages: vec![CosmosMsg::Bank(BankMsg::Send {
|
||||
from_address: env.contract.address,
|
||||
to_address: recipient,
|
||||
amount: vec![amount],
|
||||
})],
|
||||
log: vec![],
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn query<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &Extern<S, A, Q>,
|
||||
msg: QueryMsg,
|
||||
|
|
|
@ -6,6 +6,9 @@ use crate::state::{GuardianAddress, GuardianSetInfo};
|
|||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct InitMsg {
|
||||
pub gov_chain: u16,
|
||||
pub gov_address: Binary,
|
||||
|
||||
pub initial_guardian_set: GuardianSetInfo,
|
||||
pub guardian_set_expirity: u64,
|
||||
}
|
||||
|
@ -20,10 +23,6 @@ pub enum HandleMsg {
|
|||
message: Binary,
|
||||
nonce: u32
|
||||
},
|
||||
TransferFee {
|
||||
amount: Coin,
|
||||
recipient: HumanAddr,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use cosmwasm_std::{Binary, CanonicalAddr, HumanAddr, StdResult, Storage, Coin};
|
||||
use cosmwasm_std::{Binary, CanonicalAddr, HumanAddr, StdResult, Storage, Coin, Uint128};
|
||||
use cosmwasm_storage::{
|
||||
bucket, bucket_read, singleton, singleton_read, Bucket, ReadonlyBucket, ReadonlySingleton,
|
||||
Singleton,
|
||||
|
@ -26,8 +26,9 @@ pub struct ConfigInfo {
|
|||
// Period for which a guardian set stays active after it has been replaced
|
||||
pub guardian_set_expirity: u64,
|
||||
|
||||
// Contract owner address, it can make contract active/inactive
|
||||
pub owner: CanonicalAddr,
|
||||
// governance contract details
|
||||
pub gov_chain: u16,
|
||||
pub gov_address: Vec<u8>,
|
||||
|
||||
// Asset locking fee
|
||||
pub fee: Coin,
|
||||
|
@ -219,20 +220,96 @@ pub fn wrapped_asset_address_read<S: Storage>(storage: &S) -> ReadonlyBucket<S,
|
|||
}
|
||||
|
||||
|
||||
pub struct WormholeGovernance {
|
||||
pub struct GovernancePacket {
|
||||
pub module: Vec<u8>,
|
||||
pub chain: u16,
|
||||
pub action: u8,
|
||||
pub payload: Vec<u8>,
|
||||
}
|
||||
|
||||
impl WormholeGovernance {
|
||||
impl GovernancePacket {
|
||||
pub fn deserialize(data: &Vec<u8>) -> StdResult<Self> {
|
||||
let data = data.as_slice();
|
||||
let action = data.get_u8(0);
|
||||
let payload = &data[1..];
|
||||
let module = data.get_bytes32(0).to_vec();
|
||||
let chain = data.get_u16(32);
|
||||
let action = data.get_u8(34);
|
||||
let payload = data[35..].to_vec();
|
||||
|
||||
Ok(WormholeGovernance {
|
||||
Ok(GovernancePacket {
|
||||
module,
|
||||
chain,
|
||||
action,
|
||||
payload: payload.to_vec(),
|
||||
payload
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// action 1
|
||||
pub struct GuardianSetUpgrade {
|
||||
pub new_guardian_set_index: u32,
|
||||
pub new_guardian_set: GuardianSetInfo,
|
||||
}
|
||||
|
||||
impl GuardianSetUpgrade {
|
||||
pub fn deserialize(data: &Vec<u8>) -> StdResult<Self> {
|
||||
|
||||
const ADDRESS_LEN: usize = 20;
|
||||
|
||||
let data = data.as_slice();
|
||||
let new_guardian_set_index = data.get_u32(0);
|
||||
|
||||
let n_guardians = data.get_u8(4);
|
||||
|
||||
let mut addresses = vec![];
|
||||
|
||||
for i in 0..n_guardians {
|
||||
let pos = 5 + (i as usize) * ADDRESS_LEN;
|
||||
if pos + ADDRESS_LEN > data.len() {
|
||||
return ContractError::InvalidVAA.std_err();
|
||||
}
|
||||
|
||||
addresses.push(GuardianAddress {
|
||||
bytes: data[pos..pos + ADDRESS_LEN].to_vec().into(),
|
||||
});
|
||||
}
|
||||
|
||||
let new_guardian_set = GuardianSetInfo {
|
||||
addresses,
|
||||
expiration_time: 0
|
||||
};
|
||||
|
||||
return Ok(
|
||||
GuardianSetUpgrade {
|
||||
new_guardian_set_index,
|
||||
new_guardian_set
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// action 2
|
||||
pub struct TransferFee {
|
||||
pub amount: Coin,
|
||||
pub recipient: CanonicalAddr,
|
||||
}
|
||||
|
||||
impl TransferFee {
|
||||
pub fn deserialize(data: &Vec<u8>) -> StdResult<Self> {
|
||||
let data = data.as_slice();
|
||||
let recipient = data.get_address(0);
|
||||
|
||||
let amount = Uint128(data.get_u128_be(32));
|
||||
let denom = match String::from_utf8(data[48..].to_vec()) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return ContractError::InvalidVAA.std_err()
|
||||
};
|
||||
let amount = Coin {
|
||||
denom,
|
||||
amount,
|
||||
};
|
||||
Ok(TransferFee {
|
||||
amount,
|
||||
recipient
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ from terra_sdk.core.wasm import (
|
|||
MsgStoreCode,
|
||||
MsgInstantiateContract,
|
||||
MsgExecuteContract,
|
||||
MsgMigrateContract,
|
||||
)
|
||||
from terra_sdk.util.contract import get_code_id, get_contract_address, read_file_as_b64
|
||||
import os
|
||||
|
@ -74,9 +75,11 @@ class ContractQuerier:
|
|||
|
||||
class Contract:
|
||||
@staticmethod
|
||||
async def create(code_id, **kwargs):
|
||||
async def create(code_id, migratable=False, **kwargs):
|
||||
kwargs = convert_contracts_to_addr(kwargs)
|
||||
instantiate = MsgInstantiateContract(deployer.key.acc_address, code_id, kwargs)
|
||||
instantiate = MsgInstantiateContract(
|
||||
deployer.key.acc_address, code_id, kwargs, migratable=migratable
|
||||
)
|
||||
result = await sign_and_broadcast(instantiate)
|
||||
return Contract(get_contract_address(result))
|
||||
|
||||
|
@ -97,6 +100,15 @@ class Contract:
|
|||
def query(self):
|
||||
return ContractQuerier(self.address)
|
||||
|
||||
async def migrate(self, new_code_id):
|
||||
migrate = MsgMigrateContract(
|
||||
contract=self.address,
|
||||
migrate_msg={},
|
||||
new_code_id=new_code_id,
|
||||
owner=deployer.key.acc_address,
|
||||
)
|
||||
return await sign_and_broadcast(migrate)
|
||||
|
||||
|
||||
def convert_contracts_to_addr(obj):
|
||||
if type(obj) == dict:
|
||||
|
@ -128,15 +140,29 @@ def assemble_vaa(emitter_chain, emitter_address, payload):
|
|||
async def main():
|
||||
code_ids = await store_contracts()
|
||||
print(code_ids)
|
||||
|
||||
# fake governance contract on solana
|
||||
GOV_CHAIN = 1
|
||||
GOV_ADDRESS = b"0" * 32
|
||||
|
||||
wormhole = await Contract.create(
|
||||
code_id=code_ids["wormhole"],
|
||||
gov_chain=GOV_CHAIN,
|
||||
gov_address=base64.b64encode(GOV_ADDRESS).decode("utf-8"),
|
||||
guardian_set_expirity=10 ** 15,
|
||||
initial_guardian_set={"addresses": [], "expiration_time": 10 ** 15},
|
||||
migratable=True,
|
||||
)
|
||||
|
||||
# TODO:
|
||||
# resp = await wormhole.migrate(code_ids["wormhole"])
|
||||
# for event in resp.logs:
|
||||
# pprint.pprint(event.events_by_type)
|
||||
|
||||
token_bridge = await Contract.create(
|
||||
code_id=code_ids["token_bridge"],
|
||||
owner=deployer.key.acc_address,
|
||||
gov_chain=GOV_CHAIN,
|
||||
gov_address=base64.b64encode(GOV_ADDRESS).decode("utf-8"),
|
||||
wormhole_contract=wormhole,
|
||||
wrapped_asset_code_id=int(code_ids["cw20_wrapped"]),
|
||||
)
|
||||
|
@ -163,9 +189,19 @@ async def main():
|
|||
bridge_canonical = bytes.fromhex(
|
||||
(await wormhole.query.query_address_hex(address=token_bridge))["hex"]
|
||||
)
|
||||
await token_bridge.register_chain(
|
||||
chain_id=3, chain_address=base64.b64encode(bridge_canonical).decode("utf-8")
|
||||
)
|
||||
|
||||
# fake a VAA from the gov contract
|
||||
module = b"token_bridge"
|
||||
module += b" " * (32 - len(module))
|
||||
chain = to_bytes(0, 2)
|
||||
action = to_bytes(0, 1)
|
||||
# chain_id chain_address (pretend there's a bridge w/ the same address on solana)
|
||||
payload = to_bytes(3, 2) + bridge_canonical
|
||||
|
||||
vaa = assemble_vaa(GOV_CHAIN, GOV_ADDRESS, module + chain + action + payload)
|
||||
|
||||
# register the chain
|
||||
await token_bridge.submit_vaa(data=base64.b64encode(vaa).decode("utf-8"))
|
||||
|
||||
resp = await token_bridge.initiate_transfer(
|
||||
asset=mock_token,
|
||||
|
@ -199,9 +235,18 @@ async def main():
|
|||
)
|
||||
|
||||
# pretend there exists another bridge contract with the same address but on solana
|
||||
await token_bridge.register_chain(
|
||||
chain_id=1, chain_address=base64.b64encode(bridge_canonical).decode("utf-8")
|
||||
)
|
||||
# fake a VAA from the gov contract
|
||||
module = b"token_bridge"
|
||||
module += b" " * (32 - len(module))
|
||||
chain = to_bytes(0, 2)
|
||||
action = to_bytes(0, 1)
|
||||
# chain_id chain_address (pretend there's a bridge w/ the same address on solana)
|
||||
payload = to_bytes(1, 2) + bridge_canonical
|
||||
|
||||
vaa = assemble_vaa(GOV_CHAIN, GOV_ADDRESS, module + chain + action + payload)
|
||||
|
||||
# register the chain
|
||||
await token_bridge.submit_vaa(data=base64.b64encode(vaa).decode("utf-8"))
|
||||
|
||||
resp = await token_bridge.create_asset_meta(
|
||||
asset_address=mock_token,
|
||||
|
|
Loading…
Reference in New Issue