260 lines
6.8 KiB
Rust
260 lines
6.8 KiB
Rust
use std::convert::TryInto;
|
|
|
|
use schemars::JsonSchema;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use cosmwasm_std::{StdError, StdResult, Storage};
|
|
use cosmwasm_storage::{
|
|
bucket, bucket_read, singleton, singleton_read, Bucket, ReadonlyBucket, ReadonlySingleton,
|
|
Singleton,
|
|
};
|
|
|
|
use wormhole::byte_utils::ByteUtils;
|
|
|
|
type HumanAddr = String;
|
|
|
|
pub static CONFIG_KEY: &[u8] = b"config";
|
|
pub static WRAPPED_ASSET_KEY: &[u8] = b"wrapped_asset";
|
|
pub static WRAPPED_ASSET_ADDRESS_KEY: &[u8] = b"wrapped_asset_address";
|
|
pub static BRIDGE_CONTRACTS_KEY: &[u8] = b"bridge_contracts";
|
|
pub static TOKEN_ID_HASHES_KEY: &[u8] = b"token_id_hashes";
|
|
pub static SPL_CACHE_KEY: &[u8] = b"spl_cache";
|
|
|
|
// Guardian set information
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
|
pub struct ConfigInfo {
|
|
// governance contract details
|
|
pub gov_chain: u16,
|
|
pub gov_address: Vec<u8>,
|
|
|
|
pub wormhole_contract: HumanAddr,
|
|
pub wrapped_asset_code_id: u64,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
|
pub struct SplCacheItem {
|
|
pub name: [u8; 32],
|
|
pub symbol: [u8; 32],
|
|
}
|
|
|
|
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 bridge_contracts(storage: &mut dyn Storage) -> Bucket<Vec<u8>> {
|
|
bucket(storage, BRIDGE_CONTRACTS_KEY)
|
|
}
|
|
|
|
pub fn bridge_contracts_read(storage: &dyn Storage) -> ReadonlyBucket<Vec<u8>> {
|
|
bucket_read(storage, BRIDGE_CONTRACTS_KEY)
|
|
}
|
|
|
|
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 fn spl_cache(storage: &mut dyn Storage) -> Bucket<SplCacheItem> {
|
|
bucket(storage, SPL_CACHE_KEY)
|
|
}
|
|
|
|
pub fn spl_cache_read(storage: &dyn Storage) -> ReadonlyBucket<SplCacheItem> {
|
|
bucket_read(storage, SPL_CACHE_KEY)
|
|
}
|
|
|
|
pub fn token_id_hashes(storage: &mut dyn Storage, chain: u16, address: [u8; 32]) -> Bucket<String> {
|
|
Bucket::multilevel(
|
|
storage,
|
|
&[TOKEN_ID_HASHES_KEY, &chain.to_be_bytes(), &address],
|
|
)
|
|
}
|
|
|
|
pub fn token_id_hashes_read(
|
|
storage: &mut dyn Storage,
|
|
chain: u16,
|
|
address: [u8; 32],
|
|
) -> ReadonlyBucket<String> {
|
|
ReadonlyBucket::multilevel(
|
|
storage,
|
|
&[TOKEN_ID_HASHES_KEY, &chain.to_be_bytes(), &address],
|
|
)
|
|
}
|
|
|
|
pub struct Action;
|
|
|
|
impl Action {
|
|
pub const TRANSFER: u8 = 1;
|
|
}
|
|
|
|
// 0 u8 action
|
|
// 1 [u8] payload
|
|
pub struct TokenBridgeMessage {
|
|
pub action: u8,
|
|
pub payload: Vec<u8>,
|
|
}
|
|
|
|
impl TokenBridgeMessage {
|
|
pub fn deserialize(data: &[u8]) -> StdResult<Self> {
|
|
let action = data.get_u8(0);
|
|
let payload = &data[1..];
|
|
|
|
Ok(TokenBridgeMessage {
|
|
action,
|
|
payload: payload.to_vec(),
|
|
})
|
|
}
|
|
|
|
pub fn serialize(&self) -> Vec<u8> {
|
|
[self.action.to_be_bytes().to_vec(), self.payload.clone()].concat()
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
|
#[repr(transparent)]
|
|
pub struct BoundedVec<T, const N: usize> {
|
|
vec: Vec<T>,
|
|
}
|
|
|
|
impl<T, const N: usize> BoundedVec<T, N> {
|
|
pub fn new(vec: Vec<T>) -> StdResult<Self> {
|
|
if vec.len() > N {
|
|
return Result::Err(StdError::GenericErr {
|
|
msg: format!("vector length exceeds {}", N),
|
|
});
|
|
};
|
|
Ok(Self { vec })
|
|
}
|
|
|
|
#[inline]
|
|
pub fn to_vec(&self) -> Vec<T>
|
|
where
|
|
T: Clone,
|
|
{
|
|
self.vec.clone()
|
|
}
|
|
|
|
#[inline]
|
|
pub fn len(&self) -> usize {
|
|
self.vec.len()
|
|
}
|
|
|
|
#[inline]
|
|
pub fn is_empty(&self) -> bool {
|
|
self.vec.is_empty()
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
|
pub struct TransferInfo {
|
|
pub nft_address: [u8; 32],
|
|
pub nft_chain: u16,
|
|
pub symbol: [u8; 32],
|
|
pub name: [u8; 32],
|
|
pub token_id: [u8; 32],
|
|
pub uri: BoundedVec<u8, 200>, // max 200 bytes due to Solana
|
|
pub recipient: [u8; 32],
|
|
pub recipient_chain: u16,
|
|
}
|
|
|
|
impl TransferInfo {
|
|
pub fn deserialize(data: &[u8]) -> StdResult<Self> {
|
|
let mut offset: usize = 0; // offset into data in bytes
|
|
let nft_address = data.get_const_bytes::<32>(offset);
|
|
offset += 32;
|
|
let nft_chain = data.get_u16(offset);
|
|
offset += 2;
|
|
let symbol = data.get_const_bytes::<32>(offset);
|
|
offset += 32;
|
|
let name = data.get_const_bytes::<32>(offset);
|
|
offset += 32;
|
|
let token_id = data.get_const_bytes::<32>(offset);
|
|
offset += 32;
|
|
let uri_length: usize = data.get_u8(offset).into();
|
|
offset += 1;
|
|
let uri = data.get_bytes(offset, uri_length).to_vec();
|
|
offset += uri_length;
|
|
let recipient = data.get_const_bytes::<32>(offset);
|
|
offset += 32;
|
|
let recipient_chain = data.get_u16(offset);
|
|
offset += 2;
|
|
|
|
if data.len() != offset {
|
|
return Result::Err(StdError::GenericErr {
|
|
msg: format!(
|
|
"Invalid transfer length, expected {}, but got {}",
|
|
offset,
|
|
data.len()
|
|
),
|
|
});
|
|
}
|
|
|
|
Ok(TransferInfo {
|
|
nft_address,
|
|
nft_chain,
|
|
symbol,
|
|
name,
|
|
token_id,
|
|
uri: BoundedVec::new(uri.to_vec())?,
|
|
recipient,
|
|
recipient_chain,
|
|
})
|
|
}
|
|
pub fn serialize(&self) -> Vec<u8> {
|
|
[
|
|
self.nft_address.to_vec(),
|
|
self.nft_chain.to_be_bytes().to_vec(),
|
|
self.symbol.to_vec(),
|
|
self.name.to_vec(),
|
|
self.token_id.to_vec(),
|
|
vec![self.uri.len().try_into().unwrap()], // won't panic, because uri.len() is less than 200
|
|
self.uri.to_vec(),
|
|
self.recipient.to_vec(),
|
|
self.recipient_chain.to_be_bytes().to_vec(),
|
|
]
|
|
.concat()
|
|
}
|
|
}
|
|
|
|
pub struct UpgradeContract {
|
|
pub new_contract: u64,
|
|
}
|
|
|
|
pub struct RegisterChain {
|
|
pub chain_id: u16,
|
|
pub chain_address: Vec<u8>,
|
|
}
|
|
|
|
impl UpgradeContract {
|
|
pub fn deserialize(data: &[u8]) -> StdResult<Self> {
|
|
let new_contract = data.get_u64(24);
|
|
Ok(UpgradeContract { new_contract })
|
|
}
|
|
}
|
|
|
|
impl RegisterChain {
|
|
pub fn deserialize(data: &[u8]) -> StdResult<Self> {
|
|
let chain_id = data.get_u16(0);
|
|
let chain_address = data[2..].to_vec();
|
|
|
|
Ok(RegisterChain {
|
|
chain_id,
|
|
chain_address,
|
|
})
|
|
}
|
|
}
|