wormhole/terra/contracts/token-bridge/src/state.rs

360 lines
10 KiB
Rust

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use cosmwasm_std::{CanonicalAddr, StdError, StdResult, Storage, Uint128};
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 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";
// 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,
}
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)
}
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_seq(storage: &mut dyn Storage) -> Bucket<u64> {
bucket(storage, WRAPPED_ASSET_SEQ_KEY)
}
pub fn wrapped_asset_seq_read(storage: &mut dyn Storage) -> ReadonlyBucket<u64> {
bucket_read(storage, WRAPPED_ASSET_SEQ_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)
}
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, Eq, JsonSchema)]
pub struct TransferState {
pub account: String,
pub message: Vec<u8>,
pub multiplier: Serialized128,
pub nonce: u32,
pub previous_balance: Serialized128,
pub token_address: HumanAddr,
pub token_canonical: CanonicalAddr,
}
pub fn wrapped_transfer_tmp(storage: &mut dyn Storage) -> Singleton<TransferState> {
singleton(storage, TRANSFER_TMP_KEY)
}
pub fn send_native(
storage: &mut dyn Storage,
asset_address: &CanonicalAddr,
amount: Uint128,
) -> StdResult<()> {
let mut counter_bucket = bucket(storage, NATIVE_COUNTER);
let new_total = amount
+ counter_bucket
.load(asset_address.as_slice())
.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",
));
}
counter_bucket.save(asset_address.as_slice(), &new_total)
}
pub fn receive_native(
storage: &mut dyn Storage,
asset_address: &CanonicalAddr,
amount: Uint128,
) -> StdResult<()> {
let mut counter_bucket = bucket(storage, NATIVE_COUNTER);
let total: Uint128 = counter_bucket.load(asset_address.as_slice())?;
let result = total.checked_sub(amount)?;
counter_bucket.save(asset_address.as_slice(), &result)
}
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, Eq, JsonSchema)]
pub struct TransferInfo {
pub amount: (u128, u128),
pub token_address: [u8; 32],
pub token_chain: u16,
pub recipient: [u8; 32],
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);
let token_address = data.get_const_bytes(32);
let token_chain = data.get_u16(64);
let recipient = data.get_const_bytes(66);
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(),
self.token_address.to_vec(),
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
// 100 [u8; 32] sender_address
// 132 [u8] payload
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct TransferWithPayloadInfo {
pub amount: (u128, u128),
pub token_address: [u8; 32],
pub token_chain: u16,
pub recipient: [u8; 32],
pub recipient_chain: u16,
pub sender_address: [u8; 32],
pub payload: Vec<u8>,
}
impl TransferWithPayloadInfo {
pub fn deserialize(data: &Vec<u8>) -> StdResult<Self> {
let data = data.as_slice();
let amount = data.get_u256(0);
let token_address = 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);
let payload = TransferWithPayloadInfo::get_payload(data);
Ok(TransferWithPayloadInfo {
amount,
token_address,
token_chain,
recipient,
recipient_chain,
sender_address,
payload,
})
}
pub fn serialize(&self) -> Vec<u8> {
[
self.amount.0.to_be_bytes().to_vec(),
self.amount.1.to_be_bytes().to_vec(),
self.token_address.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()
}
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,
token_chain: self.token_chain,
recipient: self.recipient,
recipient_chain: self.recipient_chain,
fee: (0, 0),
}
}
}
// 0 [32]uint8 TokenAddress
// 32 uint16 TokenChain
// 34 uint8 Decimals
// 35 [32]uint8 Symbol
// 67 [32]uint8 Name
pub struct AssetMeta {
pub token_address: Vec<u8>,
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();
let token_address = data.get_bytes32(0).to_vec();
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> {
[
self.token_address.clone(),
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,
})
}
}