diff --git a/terra/contracts/token-bridge/src/contract.rs b/terra/contracts/token-bridge/src/contract.rs index fd1e39468..7b16b3707 100644 --- a/terra/contracts/token-bridge/src/contract.rs +++ b/terra/contracts/token-bridge/src/contract.rs @@ -83,6 +83,7 @@ pub fn handle( amount, recipient_chain, recipient, + fee, nonce, } => handle_initiate_transfer( deps, @@ -91,6 +92,7 @@ pub fn handle( amount, recipient_chain, recipient.as_slice().to_vec(), + fee, nonce, ), HandleMsg::SubmitVaa { data } => submit_vaa(deps, env, &data), @@ -337,10 +339,13 @@ fn handle_complete_transfer( let token_chain = transfer_info.token_chain; let target_address = (&transfer_info.recipient.as_slice()).get_address(0); - let (not_supported_amount, amount) = transfer_info.amount; + let (not_supported_amount, mut amount) = transfer_info.amount; + let (not_supported_fee, fee) = transfer_info.fee; + + amount -= fee; // Check high 128 bit of amount value to be empty - if not_supported_amount != 0 { + if not_supported_amount != 0 || not_supported_fee != 0 { return ContractError::AmountTooHigh.std_err(); } @@ -359,15 +364,27 @@ fn handle_complete_transfer( .human_address(&target_address) .or_else(|_| ContractError::WrongTargetAddressFormat.std_err())?; - Ok(HandleResponse { - messages: vec![CosmosMsg::Wasm(WasmMsg::Execute { + let mut messages = vec![CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: contract_addr.clone(), + msg: to_binary(&WrappedMsg::Mint { + recipient: recipient.clone(), + amount: Uint128::from(amount), + })?, + send: vec![], + })]; + if fee != 0 { + messages.push(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: contract_addr.clone(), msg: to_binary(&WrappedMsg::Mint { - recipient: recipient.clone(), - amount: Uint128::from(amount), + recipient: env.message.sender.clone(), + amount: Uint128::from(fee), })?, send: vec![], - })], + })) + } + + Ok(HandleResponse { + messages, log: vec![ log("action", "complete_transfer_wrapped"), log("contract", contract_addr), @@ -384,15 +401,29 @@ fn handle_complete_transfer( let recipient = deps.api.human_address(&target_address)?; let contract_addr = deps.api.human_address(&token_address)?; - Ok(HandleResponse { - messages: vec![CosmosMsg::Wasm(WasmMsg::Execute { + + let mut messages = vec![CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: contract_addr.clone(), + msg: to_binary(&TokenMsg::Transfer { + recipient: recipient.clone(), + amount: Uint128::from(amount), + })?, + send: vec![], + })]; + + if fee != 0 { + messages.push(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: contract_addr.clone(), msg: to_binary(&TokenMsg::Transfer { - recipient: recipient.clone(), - amount: Uint128::from(amount), + recipient: env.message.sender.clone(), + amount: Uint128::from(fee), })?, send: vec![], - })], + })) + } + + Ok(HandleResponse { + messages, log: vec![ log("action", "complete_transfer_native"), log("recipient", recipient), @@ -411,6 +442,7 @@ fn handle_initiate_transfer( amount: Uint128, recipient_chain: u16, recipient: Vec, + fee: Uint128, nonce: u32, ) -> StdResult { // if recipient_chain == CHAIN_ID { @@ -421,6 +453,10 @@ fn handle_initiate_transfer( return ContractError::AmountTooLow.std_err(); } + if fee > amount { + return Err(StdError::generic_err("fee greater than sent amount")) + } + let asset_chain: u16; let asset_address: Vec; @@ -471,6 +507,7 @@ fn handle_initiate_transfer( amount: (0, amount.u128()), recipient_chain, recipient: recipient.clone(), + fee: (0, fee.u128()), }; let token_bridge_message = TokenBridgeMessage { diff --git a/terra/contracts/token-bridge/src/msg.rs b/terra/contracts/token-bridge/src/msg.rs index 8ca18bd15..32054c280 100644 --- a/terra/contracts/token-bridge/src/msg.rs +++ b/terra/contracts/token-bridge/src/msg.rs @@ -24,6 +24,7 @@ pub enum HandleMsg { amount: Uint128, recipient_chain: u16, recipient: Binary, + fee: Uint128, nonce: u32, }, diff --git a/terra/contracts/token-bridge/src/state.rs b/terra/contracts/token-bridge/src/state.rs index b5a600d08..088965132 100644 --- a/terra/contracts/token-bridge/src/state.rs +++ b/terra/contracts/token-bridge/src/state.rs @@ -89,65 +89,65 @@ impl TokenBridgeMessage { } } -// 0 u16 token_chain -// 2 [u8; 32] token_address -// 34 u256 amount -// 66 u16 recipient_chain -// 68 [u8; 32] recipient +// 0 u256 amount +// 32 [u8; 32] token_address +// 64 u16 token_chain +// 66 [u8; 32] recipient +// 98 u16 recipient_chain +// 100 u256 fee pub struct TransferInfo { - pub token_chain: u16, - pub token_address: Vec, pub amount: (u128, u128), + pub token_address: Vec, + pub token_chain: u16, pub recipient_chain: u16, pub recipient: Vec, + pub fee: (u128, u128), } impl TransferInfo { pub fn deserialize(data: &Vec) -> StdResult { let data = data.as_slice(); - let token_chain = data.get_u16(0); - let token_address = data.get_bytes32(2).to_vec(); - let amount = data.get_u256(34); - let recipient_chain = data.get_u16(66); - let recipient = data.get_bytes32(68).to_vec(); + let amount = data.get_u256(0); + let token_address = data.get_bytes32(32).to_vec(); + let token_chain = data.get_u16(64); + let recipient = data.get_bytes32(66).to_vec(); + let recipient_chain = data.get_u16(98); + let fee = data.get_u256(100); Ok(TransferInfo { - token_chain, - token_address, amount, - recipient_chain, + token_address, + token_chain, recipient, + recipient_chain, + fee, }) } pub fn serialize(&self) -> Vec { [ - self.token_chain.to_be_bytes().to_vec(), - self.token_address.clone(), self.amount.0.to_be_bytes().to_vec(), self.amount.1.to_be_bytes().to_vec(), - self.recipient_chain.to_be_bytes().to_vec(), + self.token_address.clone(), + 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() } } -//PayloadID uint8 = 2 -// // Address of the token. Left-zero-padded if shorter than 32 bytes -// TokenAddress [32]uint8 -// // Chain ID of the token -// TokenChain uint16 -// // Number of decimals of the token -// Decimals uint8 -// // Symbol of the token (UTF-8) -// Symbol [32]uint8 -// // Name of the token (UTF-8) -// Name [32]uint8 +// 0 [32]uint8 TokenAddress +// 32 uint16 TokenChain +// 34 uint8 Decimals +// 35 [32]uint8 Symbol +// 67 [32]uint8 Name pub struct AssetMeta { - pub token_chain: u16, pub token_address: Vec, + pub token_chain: u16, pub decimals: u8, pub symbol: Vec, pub name: Vec, @@ -156,8 +156,8 @@ pub struct AssetMeta { impl AssetMeta { pub fn deserialize(data: &Vec) -> StdResult { let data = data.as_slice(); - let token_chain = data.get_u16(0); - let token_address = data.get_bytes32(2).to_vec(); + 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(); @@ -173,8 +173,8 @@ impl AssetMeta { pub fn serialize(&self) -> Vec { [ - self.token_chain.to_be_bytes().to_vec(), 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(), diff --git a/terra/contracts/wormhole/src/state.rs b/terra/contracts/wormhole/src/state.rs index a0a5f7eb5..70a508fed 100644 --- a/terra/contracts/wormhole/src/state.rs +++ b/terra/contracts/wormhole/src/state.rs @@ -42,7 +42,7 @@ pub struct ConfigInfo { pub struct ParsedVAA { pub version: u8, pub guardian_set_index: u32, - pub timestamp: u64, + pub timestamp: u32, pub nonce: u32, pub len_signers: u8, @@ -68,13 +68,13 @@ impl ParsedVAA { 1 [65]uint8 signature body: - 0 uint64 timestamp (unix in seconds) - 8 uint32 nonce - 12 uint16 emitter_chain - 14 [32]uint8 emitter_address - 46 uint64 sequence - 46 uint8 consistency_level - 54 []uint8 payload + 0 uint32 timestamp (unix in seconds) + 4 uint32 nonce + 8 uint16 emitter_chain + 10 [32]uint8 emitter_address + 42 uint64 sequence + 50 uint8 consistency_level + 51 []uint8 payload */ pub const HEADER_LEN: usize = 6; @@ -83,12 +83,12 @@ impl ParsedVAA { pub const GUARDIAN_SET_INDEX_POS: usize = 1; pub const LEN_SIGNER_POS: usize = 5; - pub const VAA_NONCE_POS: usize = 8; - pub const VAA_EMITTER_CHAIN_POS: usize = 12; - pub const VAA_EMITTER_ADDRESS_POS: usize = 14; - pub const VAA_SEQUENCE_POS: usize = 46; - pub const VAA_CONSISTENCY_LEVEL_POS: usize = 54; - pub const VAA_PAYLOAD_POS: usize = 55; + pub const VAA_NONCE_POS: usize = 4; + pub const VAA_EMITTER_CHAIN_POS: usize = 8; + pub const VAA_EMITTER_ADDRESS_POS: usize = 10; + pub const VAA_SEQUENCE_POS: usize = 42; + pub const VAA_CONSISTENCY_LEVEL_POS: usize = 50; + pub const VAA_PAYLOAD_POS: usize = 51; // Signature data offsets in the signature block pub const SIG_DATA_POS: usize = 1; @@ -124,7 +124,7 @@ impl ParsedVAA { return ContractError::InvalidVAA.std_err(); } - let timestamp = data.get_u64(body_offset); + let timestamp = data.get_u32(body_offset); let nonce = data.get_u32(body_offset + Self::VAA_NONCE_POS); let emitter_chain = data.get_u16(body_offset + Self::VAA_EMITTER_CHAIN_POS); let emitter_address = data @@ -402,31 +402,29 @@ mod tests { #[test] fn test_deserialize() { - let x = vec![ - 1u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 96u8, 180u8, 80u8, 111u8, 0u8, 0u8, - 0u8, 1u8, 0u8, 3u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 120u8, - 73u8, 153u8, 19u8, 90u8, 170u8, 138u8, 60u8, 165u8, 145u8, 68u8, 104u8, 133u8, 47u8, - 221u8, 219u8, 221u8, 216u8, 120u8, 157u8, 0u8, 91u8, 48u8, 44u8, 48u8, 44u8, 51u8, - 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, - 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 53u8, 54u8, 44u8, - 50u8, 51u8, 51u8, 44u8, 49u8, 44u8, 49u8, 49u8, 49u8, 44u8, 49u8, 54u8, 55u8, 44u8, - 49u8, 57u8, 48u8, 44u8, 50u8, 48u8, 51u8, 44u8, 49u8, 54u8, 44u8, 49u8, 55u8, 54u8, - 44u8, 50u8, 49u8, 56u8, 44u8, 50u8, 53u8, 49u8, 44u8, 49u8, 51u8, 49u8, 44u8, 51u8, - 57u8, 44u8, 49u8, 54u8, 44u8, 49u8, 57u8, 53u8, 44u8, 50u8, 50u8, 55u8, 44u8, 49u8, - 52u8, 57u8, 44u8, 50u8, 51u8, 54u8, 44u8, 49u8, 57u8, 48u8, 44u8, 50u8, 49u8, 50u8, - 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, - 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, - 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, - 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, - 44u8, 48u8, 44u8, 48u8, 44u8, 51u8, 44u8, 50u8, 51u8, 50u8, 44u8, 48u8, 44u8, 51u8, - 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, - 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 48u8, 44u8, 53u8, 51u8, 44u8, - 49u8, 49u8, 54u8, 44u8, 52u8, 56u8, 44u8, 49u8, 49u8, 54u8, 44u8, 49u8, 52u8, 57u8, - 44u8, 49u8, 48u8, 56u8, 44u8, 49u8, 49u8, 51u8, 44u8, 56u8, 44u8, 48u8, 44u8, 50u8, - 51u8, 50u8, 44u8, 52u8, 57u8, 44u8, 49u8, 53u8, 50u8, 44u8, 49u8, 44u8, 50u8, 56u8, - 44u8, 50u8, 48u8, 51u8, 44u8, 50u8, 49u8, 50u8, 44u8, 50u8, 50u8, 49u8, 44u8, 50u8, - 52u8, 49u8, 44u8, 56u8, 53u8, 44u8, 49u8, 48u8, 57u8, 93u8, - ]; - ParsedVAA::deserialize(x.as_slice()).unwrap(); + let x = hex::decode("080000000901007bfa71192f886ab6819fa4862e34b4d178962958d9b2e3d9437338c9e5fde1443b809d2886eaa69e0f0158ea517675d96243c9209c3fe1d94d5b19866654c6980000000b150000000500020001020304000000000000000000000000000000000000000000000000000000000000000000000a0261626364").unwrap(); + let v = ParsedVAA::deserialize(x.as_slice()).unwrap(); + assert_eq!( + v, + ParsedVAA { + version: 8, + guardian_set_index: 9, + timestamp: 2837, + nonce: 5, + len_signers: 1, + emitter_chain: 2, + emitter_address: vec![ + 0, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 + ], + sequence: 10, + consistency_level: 2, + payload: vec![97, 98, 99, 100], + hash: vec![ + 195, 10, 19, 96, 8, 61, 218, 69, 160, 238, 165, 142, 105, 119, 139, 121, 212, + 73, 238, 179, 13, 80, 245, 224, 75, 110, 163, 8, 185, 132, 55, 34 + ] + } + ); } }