terra/token_bridge: transfer native
Change-Id: I53fb27b467c96474f2980d495232ac955187775a
This commit is contained in:
parent
6076f9acc4
commit
a9e98247bc
|
@ -90,6 +90,7 @@ export async function transferFromTerra(
|
|||
recipientAddress: Uint8Array
|
||||
) {
|
||||
const nonce = Math.round(Math.random() * 100000);
|
||||
const isNativeAsset = ["uluna"].includes(tokenAddress);
|
||||
return [
|
||||
new MsgExecuteContract(
|
||||
walletAddress,
|
||||
|
@ -105,13 +106,41 @@ export async function transferFromTerra(
|
|||
},
|
||||
{ uluna: 10000 }
|
||||
),
|
||||
new MsgExecuteContract(
|
||||
isNativeAsset
|
||||
? new MsgExecuteContract(
|
||||
walletAddress,
|
||||
tokenBridgeAddress,
|
||||
{
|
||||
initiate_transfer: {
|
||||
asset: tokenAddress,
|
||||
asset: {
|
||||
amount: amount,
|
||||
info: {
|
||||
native_token: {
|
||||
denom: tokenAddress,
|
||||
},
|
||||
},
|
||||
},
|
||||
recipient_chain: recipientChain,
|
||||
recipient: Buffer.from(recipientAddress).toString("base64"),
|
||||
fee: "0",
|
||||
nonce: nonce,
|
||||
},
|
||||
},
|
||||
{ uluna: 10000, [tokenAddress]: amount }
|
||||
)
|
||||
: new MsgExecuteContract(
|
||||
walletAddress,
|
||||
tokenBridgeAddress,
|
||||
{
|
||||
initiate_transfer: {
|
||||
asset: {
|
||||
amount: amount,
|
||||
info: {
|
||||
token: {
|
||||
contract_addr: tokenAddress,
|
||||
},
|
||||
},
|
||||
},
|
||||
recipient_chain: recipientChain,
|
||||
recipient: Buffer.from(recipientAddress).toString("base64"),
|
||||
fee: "0",
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use crate::msg::WrappedRegistryResponse;
|
||||
use cosmwasm_std::{
|
||||
coin,
|
||||
log,
|
||||
to_binary,
|
||||
Api,
|
||||
BankMsg,
|
||||
Binary,
|
||||
CanonicalAddr,
|
||||
Coin,
|
||||
|
@ -33,6 +35,7 @@ use crate::{
|
|||
bridge_contracts_read,
|
||||
config,
|
||||
config_read,
|
||||
bridge_deposit,
|
||||
receive_native,
|
||||
send_native,
|
||||
wrapped_asset,
|
||||
|
@ -163,7 +166,6 @@ pub fn handle<S: Storage, A: Api, Q: Querier>(
|
|||
}
|
||||
HandleMsg::InitiateTransfer {
|
||||
asset,
|
||||
amount,
|
||||
recipient_chain,
|
||||
recipient,
|
||||
fee,
|
||||
|
@ -172,20 +174,76 @@ pub fn handle<S: Storage, A: Api, Q: Querier>(
|
|||
deps,
|
||||
env,
|
||||
asset,
|
||||
amount,
|
||||
recipient_chain,
|
||||
recipient.as_slice().to_vec(),
|
||||
fee,
|
||||
nonce,
|
||||
),
|
||||
HandleMsg::DepositTokens => deposit_tokens(deps, env),
|
||||
HandleMsg::WithdrawTokens { asset } => withdraw_tokens(deps, env, asset),
|
||||
HandleMsg::SubmitVaa { data } => submit_vaa(deps, env, &data),
|
||||
HandleMsg::CreateAssetMeta {
|
||||
asset_address,
|
||||
asset_info,
|
||||
nonce,
|
||||
} => handle_create_asset_meta(deps, env, &asset_address, nonce),
|
||||
} => handle_create_asset_meta(deps, env, asset_info, nonce),
|
||||
}
|
||||
}
|
||||
|
||||
fn deposit_tokens<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
) -> StdResult<HandleResponse> {
|
||||
for fund in env.message.sent_funds {
|
||||
let deposit_key = format!("{}:{}", env.message.sender, fund.denom);
|
||||
bridge_deposit(&mut deps.storage).update(deposit_key.as_bytes(), |amount: Option<Uint128>| {
|
||||
match amount {
|
||||
Some(v) => Ok(v + fund.amount),
|
||||
None => Ok(fund.amount)
|
||||
}
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(HandleResponse {
|
||||
messages: vec![],
|
||||
log: vec![
|
||||
log("action", "deposit_tokens"),
|
||||
],
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn withdraw_tokens<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
data: AssetInfo,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let mut messages: Vec<CosmosMsg> = vec![];
|
||||
if let AssetInfo::NativeToken { denom } = data {
|
||||
let deposit_key = format!("{}:{}", env.message.sender, denom);
|
||||
bridge_deposit(&mut deps.storage).update(deposit_key.as_bytes(), |current: Option<Uint128>| {
|
||||
match current {
|
||||
Some(v) => {
|
||||
messages.push(CosmosMsg::Bank(BankMsg::Send {
|
||||
from_address: env.contract.address.clone(),
|
||||
to_address: env.message.sender.clone(),
|
||||
amount: vec![coin(v.u128(), &denom)],
|
||||
}));
|
||||
Ok(Uint128(0))
|
||||
}
|
||||
None => Err(StdError::generic_err("no deposit found to withdraw"))
|
||||
}
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(HandleResponse {
|
||||
messages: vec![],
|
||||
log: vec![
|
||||
log("action", "withdraw_tokens"),
|
||||
],
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Handle wrapped asset registration messages
|
||||
fn handle_register_asset<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
|
@ -281,7 +339,29 @@ fn handle_attest_meta<S: Storage, A: Api, Q: Querier>(
|
|||
fn handle_create_asset_meta<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
asset_address: &HumanAddr,
|
||||
asset_info: AssetInfo,
|
||||
nonce: u32,
|
||||
) -> StdResult<HandleResponse> {
|
||||
match asset_info {
|
||||
AssetInfo::Token { contract_addr } => handle_create_asset_meta_token(
|
||||
deps,
|
||||
env,
|
||||
contract_addr,
|
||||
nonce,
|
||||
),
|
||||
AssetInfo::NativeToken { ref denom } => handle_create_asset_meta_native_token(
|
||||
deps,
|
||||
env,
|
||||
denom.clone(),
|
||||
nonce,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_create_asset_meta_token<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
asset_address: HumanAddr,
|
||||
nonce: u32,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let cfg = config_read(&deps.storage).load()?;
|
||||
|
@ -291,7 +371,7 @@ fn handle_create_asset_meta<S: Storage, A: Api, Q: Querier>(
|
|||
msg: to_binary(&TokenQuery::TokenInfo {})?,
|
||||
});
|
||||
|
||||
let asset_canonical = deps.api.canonical_address(asset_address)?;
|
||||
let asset_canonical = deps.api.canonical_address(&asset_address)?;
|
||||
let token_info: TokenInfoResponse = deps.querier.query(&request)?;
|
||||
|
||||
let meta: AssetMeta = AssetMeta {
|
||||
|
@ -327,6 +407,63 @@ fn handle_create_asset_meta<S: Storage, A: Api, Q: Querier>(
|
|||
})
|
||||
}
|
||||
|
||||
/// All ISO-4217 currency codes are 3 letters, so we can safely slice anything that is not ULUNA.
|
||||
/// https://www.xe.com/iso4217.php
|
||||
fn format_native_denom_symbol(denom: &str) -> String {
|
||||
if denom == "uluna" {
|
||||
return "LUNA".to_string();
|
||||
}
|
||||
// UUSD -> US -> UST
|
||||
denom.to_uppercase()[1..3].to_string() + "T"
|
||||
}
|
||||
|
||||
fn handle_create_asset_meta_native_token<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
denom: String,
|
||||
nonce: u32,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let cfg = config_read(&deps.storage).load()?;
|
||||
|
||||
let mut asset_id = extend_address_to_32(&build_native_id(&denom).into());
|
||||
asset_id[0] = 1;
|
||||
|
||||
let symbol = format_native_denom_symbol(&denom);
|
||||
|
||||
let meta: AssetMeta = AssetMeta {
|
||||
token_chain: CHAIN_ID,
|
||||
token_address: asset_id.clone(),
|
||||
decimals: 6,
|
||||
symbol: extend_string_to_32(&symbol)?,
|
||||
name: extend_string_to_32(&symbol)?,
|
||||
};
|
||||
|
||||
let token_bridge_message = TokenBridgeMessage {
|
||||
action: Action::ATTEST_META,
|
||||
payload: meta.serialize().to_vec(),
|
||||
};
|
||||
|
||||
Ok(HandleResponse {
|
||||
messages: vec![CosmosMsg::Wasm(WasmMsg::Execute {
|
||||
contract_addr: cfg.wormhole_contract,
|
||||
msg: to_binary(&WormholeHandleMsg::PostMessage {
|
||||
message: Binary::from(token_bridge_message.serialize()),
|
||||
nonce,
|
||||
})?,
|
||||
// forward coins sent to this message
|
||||
send: coins_after_tax(deps, env.message.sent_funds.clone())?,
|
||||
})],
|
||||
log: vec![
|
||||
log("meta.token_chain", CHAIN_ID),
|
||||
log("meta.symbol", symbol),
|
||||
log("meta.asset_id", hex::encode(asset_id)),
|
||||
log("meta.nonce", nonce),
|
||||
log("meta.block_time", env.block.time),
|
||||
],
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn submit_vaa<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
|
@ -395,7 +532,7 @@ fn handle_governance_payload<S: Storage, A: Api, Q: Querier>(
|
|||
|
||||
fn handle_register_chain<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
_env: Env,
|
||||
data: &Vec<u8>,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let RegisterChain {
|
||||
|
@ -432,6 +569,23 @@ fn handle_complete_transfer<S: Storage, A: Api, Q: Querier>(
|
|||
) -> StdResult<HandleResponse> {
|
||||
let transfer_info = TransferInfo::deserialize(&data)?;
|
||||
|
||||
// All terra token addresses are 20 bytes, and so start with 12 0's, if the address begins with
|
||||
// a 1 we can identify it as a fully native token.
|
||||
match transfer_info.token_address.as_slice()[0] {
|
||||
1 => handle_complete_transfer_token_native(deps, env, emitter_chain, emitter_address, data),
|
||||
_ => handle_complete_transfer_token(deps, env, emitter_chain, emitter_address, data),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_complete_transfer_token<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
emitter_chain: u16,
|
||||
emitter_address: Vec<u8>,
|
||||
data: &Vec<u8>,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let transfer_info = TransferInfo::deserialize(&data)?;
|
||||
|
||||
let expected_contract =
|
||||
bridge_contracts_read(&deps.storage).load(&emitter_chain.to_be_bytes())?;
|
||||
|
||||
|
@ -439,15 +593,14 @@ fn handle_complete_transfer<S: Storage, A: Api, Q: Querier>(
|
|||
if expected_contract != emitter_address {
|
||||
return Err(StdError::unauthorized());
|
||||
}
|
||||
|
||||
if transfer_info.recipient_chain != CHAIN_ID {
|
||||
return Err(StdError::generic_err(
|
||||
"this transfer is not directed at this chain",
|
||||
));
|
||||
}
|
||||
|
||||
let token_chain = transfer_info.token_chain;
|
||||
let target_address = (&transfer_info.recipient.as_slice()).get_address(0);
|
||||
let token_chain = transfer_info.token_chain;
|
||||
|
||||
let (not_supported_amount, mut amount) = transfer_info.amount;
|
||||
let (not_supported_fee, mut fee) = transfer_info.fee;
|
||||
|
@ -551,7 +704,7 @@ fn handle_complete_transfer<S: Storage, A: Api, Q: Querier>(
|
|||
Ok(HandleResponse {
|
||||
messages,
|
||||
log: vec![
|
||||
log("action", "complete_transfer_native"),
|
||||
log("action", "complete_transfer_token"),
|
||||
log("recipient", recipient),
|
||||
log("contract", contract_addr),
|
||||
log("amount", amount),
|
||||
|
@ -561,7 +714,117 @@ fn handle_complete_transfer<S: Storage, A: Api, Q: Querier>(
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_complete_transfer_token_native<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
emitter_chain: u16,
|
||||
emitter_address: Vec<u8>,
|
||||
data: &Vec<u8>,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let transfer_info = TransferInfo::deserialize(&data)?;
|
||||
|
||||
let expected_contract =
|
||||
bridge_contracts_read(&deps.storage).load(&emitter_chain.to_be_bytes())?;
|
||||
|
||||
// must be sent by a registered token bridge contract
|
||||
if expected_contract != emitter_address {
|
||||
return Err(StdError::unauthorized());
|
||||
}
|
||||
if transfer_info.recipient_chain != CHAIN_ID {
|
||||
return Err(StdError::generic_err(
|
||||
"this transfer is not directed at this chain",
|
||||
));
|
||||
}
|
||||
|
||||
let target_address = (&transfer_info.recipient.as_slice()).get_address(0);
|
||||
|
||||
let (not_supported_amount, mut amount) = transfer_info.amount;
|
||||
let (not_supported_fee, fee) = transfer_info.fee;
|
||||
|
||||
amount = amount.checked_sub(fee).unwrap();
|
||||
|
||||
// Check high 128 bit of amount value to be empty
|
||||
if not_supported_amount != 0 || not_supported_fee != 0 {
|
||||
return ContractError::AmountTooHigh.std_err();
|
||||
}
|
||||
|
||||
// Wipe the native byte marker and extract the serialized denom.
|
||||
let mut token_address = transfer_info.token_address.clone();
|
||||
let token_address = token_address.as_mut_slice();
|
||||
token_address[0] = 0;
|
||||
|
||||
let mut denom = token_address.to_vec();
|
||||
denom.retain(|&c| c != 0);
|
||||
let denom = String::from_utf8(denom).unwrap();
|
||||
|
||||
// note -- here the amount is the amount the recipient will receive;
|
||||
// amount + fee is the total sent
|
||||
let recipient = deps.api.human_address(&target_address)?;
|
||||
let token_address = (&*token_address).get_address(0);
|
||||
receive_native(&mut deps.storage, &token_address, Uint128(amount + fee))?;
|
||||
|
||||
let mut messages = vec![CosmosMsg::Bank(BankMsg::Send {
|
||||
from_address: env.contract.address.clone(),
|
||||
to_address: recipient.clone(),
|
||||
amount: vec![coin(amount, &denom)],
|
||||
})];
|
||||
|
||||
if fee != 0 {
|
||||
messages.push(CosmosMsg::Bank(BankMsg::Send {
|
||||
from_address: env.contract.address.clone(),
|
||||
to_address: recipient.clone(),
|
||||
amount: vec![coin(fee, &denom)],
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(HandleResponse {
|
||||
messages,
|
||||
log: vec![
|
||||
log("action", "complete_transfer_token_native"),
|
||||
log("recipient", recipient),
|
||||
log("denom", denom),
|
||||
log("amount", amount),
|
||||
],
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_initiate_transfer<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
asset: Asset,
|
||||
recipient_chain: u16,
|
||||
recipient: Vec<u8>,
|
||||
fee: Uint128,
|
||||
nonce: u32,
|
||||
) -> StdResult<HandleResponse> {
|
||||
match asset.info {
|
||||
AssetInfo::Token { contract_addr } => handle_initiate_transfer_token(
|
||||
deps,
|
||||
env,
|
||||
contract_addr,
|
||||
asset.amount,
|
||||
recipient_chain,
|
||||
recipient,
|
||||
fee,
|
||||
nonce,
|
||||
),
|
||||
AssetInfo::NativeToken { ref denom } => {
|
||||
handle_initiate_transfer_native_token(
|
||||
deps,
|
||||
env,
|
||||
denom.clone(),
|
||||
asset.amount,
|
||||
recipient_chain,
|
||||
recipient,
|
||||
fee,
|
||||
nonce,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_initiate_transfer_token<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
asset: HumanAddr,
|
||||
|
@ -574,11 +837,9 @@ fn handle_initiate_transfer<S: Storage, A: Api, Q: Querier>(
|
|||
if recipient_chain == CHAIN_ID {
|
||||
return ContractError::SameSourceAndTarget.std_err();
|
||||
}
|
||||
|
||||
if amount.is_zero() {
|
||||
return ContractError::AmountTooLow.std_err();
|
||||
}
|
||||
|
||||
if fee > amount {
|
||||
return Err(StdError::generic_err("fee greater than sent amount"));
|
||||
}
|
||||
|
@ -700,6 +961,90 @@ fn handle_initiate_transfer<S: Storage, A: Api, Q: Querier>(
|
|||
})
|
||||
}
|
||||
|
||||
fn handle_initiate_transfer_native_token<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &mut Extern<S, A, Q>,
|
||||
env: Env,
|
||||
denom: String,
|
||||
amount: Uint128,
|
||||
recipient_chain: u16,
|
||||
recipient: Vec<u8>,
|
||||
fee: Uint128,
|
||||
nonce: u32,
|
||||
) -> StdResult<HandleResponse> {
|
||||
if recipient_chain == CHAIN_ID {
|
||||
return ContractError::SameSourceAndTarget.std_err();
|
||||
}
|
||||
if amount.is_zero() {
|
||||
return ContractError::AmountTooLow.std_err();
|
||||
}
|
||||
if fee > amount {
|
||||
return Err(StdError::generic_err("fee greater than sent amount"));
|
||||
}
|
||||
|
||||
let deposit_key = format!("{}:{}", env.message.sender, denom);
|
||||
bridge_deposit(&mut deps.storage).update(deposit_key.as_bytes(), |current: Option<Uint128>| {
|
||||
match current {
|
||||
Some(v) => Ok((v - amount)?),
|
||||
None => Err(StdError::generic_err("no deposit found to transfer"))
|
||||
}
|
||||
})?;
|
||||
|
||||
let cfg: ConfigInfo = config_read(&deps.storage).load()?;
|
||||
let mut messages: Vec<CosmosMsg> = vec![];
|
||||
|
||||
let asset_chain: u16 = CHAIN_ID;
|
||||
let mut asset_address: Vec<u8> = build_native_id(&denom);
|
||||
|
||||
send_native(&mut deps.storage, &asset_address[..].into(), amount)?;
|
||||
|
||||
// Mark the first byte of the address to distinguish it as native.
|
||||
asset_address = extend_address_to_32(&asset_address.into());
|
||||
asset_address[0] = 1;
|
||||
|
||||
let transfer_info = TransferInfo {
|
||||
token_chain: asset_chain,
|
||||
token_address: asset_address.to_vec(),
|
||||
amount: (0, amount.u128()),
|
||||
recipient_chain,
|
||||
recipient: recipient.clone(),
|
||||
fee: (0, fee.u128()),
|
||||
};
|
||||
|
||||
let token_bridge_message = TokenBridgeMessage {
|
||||
action: Action::TRANSFER,
|
||||
payload: transfer_info.serialize(),
|
||||
};
|
||||
|
||||
messages.push(CosmosMsg::Wasm(WasmMsg::Execute {
|
||||
contract_addr: cfg.wormhole_contract,
|
||||
msg: to_binary(&WormholeHandleMsg::PostMessage {
|
||||
message: Binary::from(token_bridge_message.serialize()),
|
||||
nonce,
|
||||
})?,
|
||||
send: coins_after_tax(deps, env.message.sent_funds.clone())?,
|
||||
}));
|
||||
|
||||
Ok(HandleResponse {
|
||||
messages,
|
||||
log: vec![
|
||||
log("transfer.token_chain", asset_chain),
|
||||
log("transfer.token", hex::encode(asset_address)),
|
||||
log(
|
||||
"transfer.sender",
|
||||
hex::encode(extend_address_to_32(
|
||||
&deps.api.canonical_address(&env.message.sender)?,
|
||||
)),
|
||||
),
|
||||
log("transfer.recipient_chain", recipient_chain),
|
||||
log("transfer.recipient", hex::encode(recipient)),
|
||||
log("transfer.amount", amount),
|
||||
log("transfer.nonce", nonce),
|
||||
log("transfer.block_time", env.block.time),
|
||||
],
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn query<S: Storage, A: Api, Q: Querier>(
|
||||
deps: &Extern<S, A, Q>,
|
||||
msg: QueryMsg,
|
||||
|
@ -734,6 +1079,16 @@ fn build_asset_id(chain: u16, address: &[u8]) -> Vec<u8> {
|
|||
hasher.finalize().to_vec()
|
||||
}
|
||||
|
||||
// Produce a 20 byte asset "address" from a native terra denom.
|
||||
fn build_native_id(denom: &str) -> Vec<u8> {
|
||||
let mut asset_address: Vec<u8> = denom.clone().as_bytes().to_vec();
|
||||
asset_address.reverse();
|
||||
asset_address.extend(vec![0u8; 20 - denom.len()]);
|
||||
asset_address.reverse();
|
||||
assert_eq!(asset_address.len(), 20);
|
||||
asset_address
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use cosmwasm_std::{
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
use cosmwasm_std::{
|
||||
Binary,
|
||||
HumanAddr,
|
||||
Uint128,
|
||||
};
|
||||
use cosmwasm_std::{Binary, HumanAddr, Uint128};
|
||||
use schemars::JsonSchema;
|
||||
use terraswap::asset::{Asset, AssetInfo};
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
|
@ -26,9 +23,13 @@ pub enum HandleMsg {
|
|||
asset_id: Binary,
|
||||
},
|
||||
|
||||
DepositTokens,
|
||||
WithdrawTokens {
|
||||
asset: AssetInfo,
|
||||
},
|
||||
|
||||
InitiateTransfer {
|
||||
asset: HumanAddr,
|
||||
amount: Uint128,
|
||||
asset: Asset,
|
||||
recipient_chain: u16,
|
||||
recipient: Binary,
|
||||
fee: Uint128,
|
||||
|
@ -40,7 +41,7 @@ pub enum HandleMsg {
|
|||
},
|
||||
|
||||
CreateAssetMeta {
|
||||
asset_address: HumanAddr,
|
||||
asset_info: AssetInfo,
|
||||
nonce: u32,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ 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: &[u8] = b"bridge_contracts";
|
||||
pub static BRIDGE_DEPOSITS: &[u8] = b"bridge_deposits";
|
||||
pub static NATIVE_COUNTER: &[u8] = b"native_counter";
|
||||
|
||||
// Guardian set information
|
||||
|
@ -50,6 +51,14 @@ pub fn config_read<S: Storage>(storage: &S) -> ReadonlySingleton<S, ConfigInfo>
|
|||
singleton_read(storage, CONFIG_KEY)
|
||||
}
|
||||
|
||||
pub fn bridge_deposit<S: Storage>(storage: &mut S) -> Bucket<S, Uint128> {
|
||||
bucket(BRIDGE_DEPOSITS, storage)
|
||||
}
|
||||
|
||||
pub fn bridge_deposit_read<S: Storage>(storage: &S) -> ReadonlyBucket<S, Uint128> {
|
||||
bucket_read(BRIDGE_DEPOSITS, storage)
|
||||
}
|
||||
|
||||
pub fn bridge_contracts<S: Storage>(storage: &mut S) -> Bucket<S, Vec<u8>> {
|
||||
bucket(BRIDGE_CONTRACTS, storage)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue