2022-06-16 09:48:01 -07:00
|
|
|
use schemars::JsonSchema;
|
|
|
|
use serde::{
|
|
|
|
Deserialize,
|
|
|
|
Serialize,
|
|
|
|
};
|
|
|
|
|
|
|
|
use cosmwasm_std::{
|
2022-06-07 08:36:21 -07:00
|
|
|
Addr,
|
2022-06-16 09:48:01 -07:00
|
|
|
StdError,
|
|
|
|
StdResult,
|
|
|
|
Storage,
|
|
|
|
Uint128,
|
|
|
|
};
|
|
|
|
use cosmwasm_storage::{
|
|
|
|
bucket,
|
|
|
|
bucket_read,
|
|
|
|
singleton,
|
|
|
|
singleton_read,
|
|
|
|
Bucket,
|
|
|
|
ReadonlyBucket,
|
|
|
|
ReadonlySingleton,
|
|
|
|
Singleton,
|
|
|
|
};
|
|
|
|
|
|
|
|
use wormhole::byte_utils::ByteUtils;
|
|
|
|
|
2022-06-07 08:36:21 -07:00
|
|
|
use crate::token_address::{ExternalTokenId, WrappedCW20};
|
|
|
|
|
2022-06-16 09:48:01 -07:00
|
|
|
type HumanAddr = String;
|
|
|
|
|
|
|
|
pub static CONFIG_KEY: &[u8] = b"config";
|
|
|
|
pub static TRANSFER_TMP_KEY: &[u8] = b"transfer_tmp";
|
|
|
|
pub static WRAPPED_ASSET_KEY: &[u8] = b"wrapped_asset";
|
|
|
|
pub static WRAPPED_ASSET_SEQ_KEY: &[u8] = b"wrapped_seq_asset";
|
|
|
|
pub static WRAPPED_ASSET_ADDRESS_KEY: &[u8] = b"wrapped_asset_address";
|
|
|
|
pub static BRIDGE_CONTRACTS: &[u8] = b"bridge_contracts";
|
|
|
|
pub static BRIDGE_DEPOSITS: &[u8] = b"bridge_deposits";
|
|
|
|
pub static NATIVE_COUNTER: &[u8] = b"native_counter";
|
2022-06-07 08:36:21 -07:00
|
|
|
pub static BANK_TOKEN_HASHES_KEY: &[u8] = b"bank_token_hashes";
|
|
|
|
pub static NATIVE_CW20_HASHES_KEY: &[u8] = b"native_cw20_hashes";
|
2022-06-16 09:48:01 -07:00
|
|
|
|
|
|
|
// Guardian set information
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, 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,
|
|
|
|
}
|
|
|
|
|
|
|
|
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_deposit(storage: &mut dyn Storage) -> Bucket<Uint128> {
|
|
|
|
bucket(storage, BRIDGE_DEPOSITS)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn bridge_deposit_read(storage: &dyn Storage) -> ReadonlyBucket<Uint128> {
|
|
|
|
bucket_read(storage, BRIDGE_DEPOSITS)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn bridge_contracts(storage: &mut dyn Storage) -> Bucket<Vec<u8>> {
|
|
|
|
bucket(storage, BRIDGE_CONTRACTS)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn bridge_contracts_read(storage: &dyn Storage) -> ReadonlyBucket<Vec<u8>> {
|
|
|
|
bucket_read(storage, BRIDGE_CONTRACTS)
|
|
|
|
}
|
|
|
|
|
2022-06-07 08:36:21 -07:00
|
|
|
pub fn wrapped_asset(storage: &mut dyn Storage, chain: u16) -> Bucket<WrappedCW20> {
|
|
|
|
Bucket::multilevel(storage, &[WRAPPED_ASSET_KEY, &chain.to_be_bytes()])
|
2022-06-16 09:48:01 -07:00
|
|
|
}
|
|
|
|
|
2022-06-07 08:36:21 -07:00
|
|
|
pub fn wrapped_asset_read(storage: &dyn Storage, chain: u16) -> ReadonlyBucket<WrappedCW20> {
|
|
|
|
ReadonlyBucket::multilevel(storage, &[WRAPPED_ASSET_KEY, &chain.to_be_bytes()])
|
2022-06-16 09:48:01 -07:00
|
|
|
}
|
|
|
|
|
2022-06-07 08:36:21 -07:00
|
|
|
pub fn wrapped_asset_seq(storage: &mut dyn Storage, chain: u16) -> Bucket<u64> {
|
|
|
|
Bucket::multilevel(storage, &[WRAPPED_ASSET_KEY, &chain.to_be_bytes()])
|
2022-06-16 09:48:01 -07:00
|
|
|
}
|
|
|
|
|
2022-06-07 08:36:21 -07:00
|
|
|
pub fn wrapped_asset_seq_read(storage: &mut dyn Storage, chain: u16) -> ReadonlyBucket<u64> {
|
|
|
|
ReadonlyBucket::multilevel(storage, &[WRAPPED_ASSET_KEY, &chain.to_be_bytes()])
|
2022-06-16 09:48:01 -07:00
|
|
|
}
|
|
|
|
|
2022-06-07 08:36:21 -07:00
|
|
|
pub fn is_wrapped_asset(storage: &mut dyn Storage) -> Bucket<()> {
|
2022-06-16 09:48:01 -07:00
|
|
|
bucket(storage, WRAPPED_ASSET_ADDRESS_KEY)
|
|
|
|
}
|
|
|
|
|
2022-06-07 08:36:21 -07:00
|
|
|
pub fn is_wrapped_asset_read(storage: &dyn Storage) -> ReadonlyBucket<()> {
|
2022-06-16 09:48:01 -07:00
|
|
|
bucket_read(storage, WRAPPED_ASSET_ADDRESS_KEY)
|
|
|
|
}
|
|
|
|
|
2022-06-07 08:36:21 -07:00
|
|
|
pub fn bank_token_hashes(storage: &mut dyn Storage) -> Bucket<String> {
|
|
|
|
bucket(storage, BANK_TOKEN_HASHES_KEY)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn bank_token_hashes_read(storage: &dyn Storage) -> ReadonlyBucket<String> {
|
|
|
|
bucket_read(storage, BANK_TOKEN_HASHES_KEY)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn native_c20_hashes(storage: &mut dyn Storage) -> Bucket<Addr> {
|
|
|
|
bucket(storage, NATIVE_CW20_HASHES_KEY)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn native_c20_hashes_read(storage: &dyn Storage) -> ReadonlyBucket<Addr> {
|
|
|
|
bucket_read(storage, NATIVE_CW20_HASHES_KEY)
|
|
|
|
}
|
|
|
|
|
2022-06-16 09:48:01 -07:00
|
|
|
type Serialized128 = String;
|
|
|
|
|
|
|
|
/// Structure to keep track of an active CW20 transfer, required to pass state through to the reply
|
|
|
|
/// handler for submessages during a transfer.
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
|
|
|
pub struct TransferState {
|
|
|
|
pub account: String,
|
|
|
|
pub message: Vec<u8>,
|
|
|
|
pub multiplier: Serialized128,
|
|
|
|
pub nonce: u32,
|
|
|
|
pub previous_balance: Serialized128,
|
2022-06-07 08:36:21 -07:00
|
|
|
pub token_address: Addr,
|
2022-06-16 09:48:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn wrapped_transfer_tmp(storage: &mut dyn Storage) -> Singleton<TransferState> {
|
|
|
|
singleton(storage, TRANSFER_TMP_KEY)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn send_native(
|
|
|
|
storage: &mut dyn Storage,
|
2022-06-07 08:36:21 -07:00
|
|
|
asset_address: &ExternalTokenId,
|
2022-06-16 09:48:01 -07:00
|
|
|
amount: Uint128,
|
|
|
|
) -> StdResult<()> {
|
|
|
|
let mut counter_bucket = bucket(storage, NATIVE_COUNTER);
|
|
|
|
let new_total = amount
|
|
|
|
+ counter_bucket
|
2022-06-07 08:36:21 -07:00
|
|
|
.load(asset_address.serialize().as_slice())
|
2022-06-16 09:48:01 -07:00
|
|
|
.unwrap_or(Uint128::zero());
|
|
|
|
if new_total > Uint128::new(u64::MAX as u128) {
|
|
|
|
return Err(StdError::generic_err(
|
|
|
|
"transfer exceeds max outstanding bridged token amount",
|
|
|
|
));
|
|
|
|
}
|
2022-06-07 08:36:21 -07:00
|
|
|
counter_bucket.save(asset_address.serialize().as_slice(), &new_total)
|
2022-06-16 09:48:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn receive_native(
|
|
|
|
storage: &mut dyn Storage,
|
2022-06-07 08:36:21 -07:00
|
|
|
asset_address: &ExternalTokenId,
|
2022-06-16 09:48:01 -07:00
|
|
|
amount: Uint128,
|
|
|
|
) -> StdResult<()> {
|
|
|
|
let mut counter_bucket = bucket(storage, NATIVE_COUNTER);
|
2022-06-07 08:36:21 -07:00
|
|
|
let total: Uint128 = counter_bucket.load(asset_address.serialize().as_slice())?;
|
2022-06-16 09:48:01 -07:00
|
|
|
let result = total.checked_sub(amount)?;
|
2022-06-07 08:36:21 -07:00
|
|
|
counter_bucket.save(asset_address.serialize().as_slice(), &result)
|
2022-06-16 09:48:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Action;
|
|
|
|
|
|
|
|
impl Action {
|
|
|
|
pub const TRANSFER: u8 = 1;
|
|
|
|
pub const ATTEST_META: u8 = 2;
|
|
|
|
pub const TRANSFER_WITH_PAYLOAD: u8 = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0 u8 action
|
|
|
|
// 1 [u8] payload
|
|
|
|
|
|
|
|
pub struct TokenBridgeMessage {
|
|
|
|
pub action: u8,
|
|
|
|
pub payload: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TokenBridgeMessage {
|
|
|
|
pub fn deserialize(data: &Vec<u8>) -> StdResult<Self> {
|
|
|
|
let data = data.as_slice();
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0 u256 amount
|
|
|
|
// 32 [u8; 32] token_address
|
|
|
|
// 64 u16 token_chain
|
|
|
|
// 66 [u8; 32] recipient
|
|
|
|
// 98 u16 recipient_chain
|
|
|
|
// 100 u256 fee
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
|
|
|
pub struct TransferInfo {
|
|
|
|
pub amount: (u128, u128),
|
2022-06-07 08:36:21 -07:00
|
|
|
pub token_address: ExternalTokenId,
|
2022-06-16 09:48:01 -07:00
|
|
|
pub token_chain: u16,
|
2022-06-07 08:36:21 -07:00
|
|
|
pub recipient: [u8; 32],
|
2022-06-16 09:48:01 -07:00
|
|
|
pub recipient_chain: u16,
|
|
|
|
pub fee: (u128, u128),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TransferInfo {
|
|
|
|
pub fn deserialize(data: &Vec<u8>) -> StdResult<Self> {
|
|
|
|
let data = data.as_slice();
|
|
|
|
let amount = data.get_u256(0);
|
2022-06-07 08:36:21 -07:00
|
|
|
let token_address = ExternalTokenId::deserialize(data.get_const_bytes::<32>(32));
|
2022-06-16 09:48:01 -07:00
|
|
|
let token_chain = data.get_u16(64);
|
2022-06-07 08:36:21 -07:00
|
|
|
let recipient = data.get_const_bytes::<32>(66);
|
2022-06-16 09:48:01 -07:00
|
|
|
let recipient_chain = data.get_u16(98);
|
|
|
|
let fee = data.get_u256(100);
|
|
|
|
|
|
|
|
Ok(TransferInfo {
|
|
|
|
amount,
|
|
|
|
token_address,
|
|
|
|
token_chain,
|
|
|
|
recipient,
|
|
|
|
recipient_chain,
|
|
|
|
fee,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
pub fn serialize(&self) -> Vec<u8> {
|
|
|
|
[
|
|
|
|
self.amount.0.to_be_bytes().to_vec(),
|
|
|
|
self.amount.1.to_be_bytes().to_vec(),
|
2022-06-07 08:36:21 -07:00
|
|
|
self.token_address.serialize().to_vec(),
|
2022-06-16 09:48:01 -07:00
|
|
|
self.token_chain.to_be_bytes().to_vec(),
|
|
|
|
self.recipient.to_vec(),
|
|
|
|
self.recipient_chain.to_be_bytes().to_vec(),
|
|
|
|
self.fee.0.to_be_bytes().to_vec(),
|
|
|
|
self.fee.1.to_be_bytes().to_vec(),
|
|
|
|
]
|
|
|
|
.concat()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0 u256 amount
|
|
|
|
// 32 [u8; 32] token_address
|
|
|
|
// 64 u16 token_chain
|
|
|
|
// 66 [u8; 32] recipient
|
|
|
|
// 98 u16 recipient_chain
|
2022-06-21 14:30:33 -07:00
|
|
|
// 100 [u8; 32] sender_address
|
2022-06-16 09:48:01 -07:00
|
|
|
// 132 [u8] payload
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
|
|
|
pub struct TransferWithPayloadInfo {
|
2022-06-21 14:30:33 -07:00
|
|
|
pub amount: (u128, u128),
|
|
|
|
pub token_address: ExternalTokenId,
|
|
|
|
pub token_chain: u16,
|
|
|
|
pub recipient: [u8; 32],
|
|
|
|
pub recipient_chain: u16,
|
|
|
|
pub sender_address: [u8; 32],
|
2022-06-16 09:48:01 -07:00
|
|
|
pub payload: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TransferWithPayloadInfo {
|
|
|
|
pub fn deserialize(data: &Vec<u8>) -> StdResult<Self> {
|
2022-06-21 14:30:33 -07:00
|
|
|
let data = data.as_slice();
|
|
|
|
let amount = data.get_u256(0);
|
|
|
|
let token_address = ExternalTokenId::deserialize(data.get_const_bytes::<32>(32));
|
|
|
|
let token_chain = data.get_u16(64);
|
|
|
|
let recipient = data.get_const_bytes::<32>(66);
|
|
|
|
let recipient_chain = data.get_u16(98);
|
|
|
|
let sender_address = data.get_const_bytes::<32>(100);
|
2022-06-16 09:48:01 -07:00
|
|
|
let payload = TransferWithPayloadInfo::get_payload(data);
|
|
|
|
|
|
|
|
Ok(TransferWithPayloadInfo {
|
2022-06-21 14:30:33 -07:00
|
|
|
amount,
|
|
|
|
token_address,
|
|
|
|
token_chain,
|
|
|
|
recipient,
|
|
|
|
recipient_chain,
|
|
|
|
sender_address,
|
2022-06-16 09:48:01 -07:00
|
|
|
payload,
|
|
|
|
})
|
2022-06-21 14:30:33 -07:00
|
|
|
|
2022-06-16 09:48:01 -07:00
|
|
|
}
|
2022-06-21 14:30:33 -07:00
|
|
|
|
2022-06-16 09:48:01 -07:00
|
|
|
pub fn serialize(&self) -> Vec<u8> {
|
2022-06-21 14:30:33 -07:00
|
|
|
[
|
|
|
|
self.amount.0.to_be_bytes().to_vec(),
|
|
|
|
self.amount.1.to_be_bytes().to_vec(),
|
|
|
|
self.token_address.serialize().to_vec(),
|
|
|
|
self.token_chain.to_be_bytes().to_vec(),
|
|
|
|
self.recipient.to_vec(),
|
|
|
|
self.recipient_chain.to_be_bytes().to_vec(),
|
|
|
|
self.sender_address.to_vec(),
|
|
|
|
self.payload.clone(),
|
|
|
|
]
|
|
|
|
.concat()
|
2022-06-16 09:48:01 -07:00
|
|
|
}
|
2022-06-21 14:30:33 -07:00
|
|
|
|
|
|
|
pub fn get_payload(data: &[u8]) -> Vec<u8> {
|
|
|
|
data[132..].to_vec()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Convert [`TransferWithPayloadInfo`] into [`TransferInfo`] for the
|
|
|
|
/// purpose of handling them uniformly. Transfers with payload have 0 fees.
|
|
|
|
pub fn as_transfer_info(&self) -> TransferInfo {
|
|
|
|
TransferInfo {
|
|
|
|
amount: self.amount,
|
|
|
|
token_address: self.token_address.clone(),
|
|
|
|
token_chain: self.token_chain,
|
|
|
|
recipient: self.recipient,
|
|
|
|
recipient_chain: self.recipient_chain,
|
|
|
|
fee: (0, 0),
|
|
|
|
}
|
2022-06-16 09:48:01 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0 [32]uint8 TokenAddress
|
|
|
|
// 32 uint16 TokenChain
|
|
|
|
// 34 uint8 Decimals
|
|
|
|
// 35 [32]uint8 Symbol
|
|
|
|
// 67 [32]uint8 Name
|
|
|
|
|
|
|
|
pub struct AssetMeta {
|
2022-06-07 08:36:21 -07:00
|
|
|
pub token_address: ExternalTokenId,
|
2022-06-16 09:48:01 -07:00
|
|
|
pub token_chain: u16,
|
|
|
|
pub decimals: u8,
|
|
|
|
pub symbol: Vec<u8>,
|
|
|
|
pub name: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AssetMeta {
|
|
|
|
pub fn deserialize(data: &Vec<u8>) -> StdResult<Self> {
|
|
|
|
let data = data.as_slice();
|
2022-06-07 08:36:21 -07:00
|
|
|
let token_address = ExternalTokenId::deserialize(data.get_const_bytes::<32>(0));
|
2022-06-16 09:48:01 -07:00
|
|
|
let token_chain = data.get_u16(32);
|
|
|
|
let decimals = data.get_u8(34);
|
|
|
|
let symbol = data.get_bytes32(35).to_vec();
|
|
|
|
let name = data.get_bytes32(67).to_vec();
|
|
|
|
|
|
|
|
Ok(AssetMeta {
|
|
|
|
token_chain,
|
|
|
|
token_address,
|
|
|
|
decimals,
|
|
|
|
symbol,
|
|
|
|
name,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn serialize(&self) -> Vec<u8> {
|
|
|
|
[
|
2022-06-07 08:36:21 -07:00
|
|
|
self.token_address.serialize().to_vec(),
|
2022-06-16 09:48:01 -07:00
|
|
|
self.token_chain.to_be_bytes().to_vec(),
|
|
|
|
self.decimals.to_be_bytes().to_vec(),
|
|
|
|
self.symbol.clone(),
|
|
|
|
self.name.clone(),
|
|
|
|
]
|
|
|
|
.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: &Vec<u8>) -> StdResult<Self> {
|
|
|
|
let data = data.as_slice();
|
|
|
|
let new_contract = data.get_u64(24);
|
|
|
|
Ok(UpgradeContract { new_contract })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|