cosmwasm: Add fromAddress to payload 3 (#1292)

* cosmwasm: fix some clippy warnings

* cosmwasm: remove fee and add msg.sender to payload 3

* cosmwasm: fix payload 3 parsing test

* cosmwasm: fix fixed payload 3 parsing test

* cosmwasm: fix fixed fixed payload 3 parsing test

* cosmwasm: update payload tests

Co-authored-by: Csongor Kiss <ckiss@jumptrading.com>
Co-authored-by: Evan Gray <battledingo@gmail.com>
This commit is contained in:
Csongor Kiss 2022-06-21 23:30:33 +02:00 committed by GitHub
parent c4da29c209
commit d3a1fa99d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 295 additions and 136 deletions

View File

@ -169,9 +169,12 @@ pub fn reply(deps: DepsMut, env: Env, _msg: Reply) -> StdResult<Response> {
Action::TRANSFER_WITH_PAYLOAD => {
let info = TransferWithPayloadInfo::deserialize(&token_bridge_message.payload)?;
Ok((
info.transfer_info,
info.as_transfer_info(),
TransferType::WithPayload {
payload: info.payload,
// put both the payload and sender_address into the payload
// field here (which we can do, since [`TransferType`] is
// parametric)
payload: (info.payload, info.sender_address),
},
))
}
@ -209,8 +212,13 @@ pub fn reply(deps: DepsMut, env: Env, _msg: Reply) -> StdResult<Response> {
TransferType::WithPayload { payload } => TokenBridgeMessage {
action: Action::TRANSFER_WITH_PAYLOAD,
payload: TransferWithPayloadInfo {
transfer_info,
payload,
amount: transfer_info.amount,
token_address: transfer_info.token_address,
token_chain: transfer_info.token_chain,
recipient: transfer_info.recipient,
recipient_chain: transfer_info.recipient_chain,
sender_address: payload.1,
payload: payload.0,
}
.serialize(),
},
@ -368,7 +376,7 @@ fn handle_register_asset(
let mut bucket = wrapped_asset(deps.storage, chain);
let result = bucket.load(&token_address.serialize()).ok();
if let Some(_) = result {
if result.is_some() {
return ContractError::AssetAlreadyRegistered.std_err();
}
@ -379,7 +387,7 @@ fn handle_register_asset(
},
)?;
let contract_address: CanonicalAddr = deps.api.addr_canonicalize(&info.sender.as_str())?;
let contract_address: CanonicalAddr = deps.api.addr_canonicalize(info.sender.as_str())?;
is_wrapped_asset(deps.storage).save(contract_address.as_slice(), &())?;
Ok(Response::new()
@ -537,7 +545,7 @@ fn handle_create_asset_meta_token(
nonce,
})?,
// forward coins sent to this message
funds: info.funds.clone(),
funds: info.funds,
}))
.add_attribute("meta.token_chain", CHAIN_ID.to_string())
.add_attribute("meta.token", asset_address)
@ -577,7 +585,7 @@ fn handle_create_asset_meta_native_token(
nonce,
})?,
// forward coins sent to this message
funds: info.funds.clone(),
funds: info.funds,
}))
.add_attribute("meta.token_chain", CHAIN_ID.to_string())
.add_attribute("meta.symbol", symbol)
@ -610,7 +618,7 @@ fn handle_complete_transfer_with_payload(
_ => ContractError::InvalidVAAAction.std_err(),
}
} else {
return ContractError::InvalidVAAAction.std_err();
ContractError::InvalidVAAAction.std_err()
}
}
@ -640,7 +648,7 @@ fn parse_and_archive_vaa(
}
let message = TokenBridgeMessage::deserialize(&vaa.payload)?;
return Ok((vaa, Either::Right(message)));
Ok((vaa, Either::Right(message)))
}
fn submit_vaa(
@ -651,9 +659,7 @@ fn submit_vaa(
) -> StdResult<Response> {
let (vaa, payload) = parse_and_archive_vaa(deps.branch(), env.clone(), data)?;
match payload {
Either::Left(governance_packet) => {
return handle_governance_payload(deps, env, &governance_packet)
}
Either::Left(governance_packet) => handle_governance_payload(deps, env, &governance_packet),
Either::Right(message) => match message.action {
Action::TRANSFER => {
let sender = info.sender.to_string();
@ -706,7 +712,7 @@ fn handle_governance_payload(
}
fn handle_upgrade_contract(_deps: DepsMut, env: Env, data: &Vec<u8>) -> StdResult<Response> {
let UpgradeContract { new_contract } = UpgradeContract::deserialize(&data)?;
let UpgradeContract { new_contract } = UpgradeContract::deserialize(data)?;
Ok(Response::new()
.add_message(CosmosMsg::Wasm(WasmMsg::Migrate {
@ -721,7 +727,7 @@ fn handle_register_chain(deps: DepsMut, _env: Env, data: &Vec<u8>) -> StdResult<
let RegisterChain {
chain_id,
chain_address,
} = RegisterChain::deserialize(&data)?;
} = RegisterChain::deserialize(data)?;
let existing = bridge_contracts_read(deps.storage).load(&chain_id.to_be_bytes());
if existing.is_ok() {
@ -738,6 +744,7 @@ fn handle_register_chain(deps: DepsMut, _env: Env, data: &Vec<u8>) -> StdResult<
.add_attribute("chain_address", hex::encode(chain_address)))
}
#[allow(clippy::too_many_arguments)]
fn handle_complete_transfer(
deps: DepsMut,
env: Env,
@ -748,7 +755,7 @@ fn handle_complete_transfer(
data: &Vec<u8>,
relayer_address: &HumanAddr,
) -> StdResult<Response> {
let transfer_info = TransferInfo::deserialize(&data)?;
let transfer_info = TransferInfo::deserialize(data)?;
let token_id = transfer_info
.token_address
.to_token_id(deps.storage, transfer_info.token_chain)?;
@ -778,6 +785,8 @@ fn handle_complete_transfer(
}
}
#[allow(clippy::too_many_arguments)]
#[allow(clippy::bind_instead_of_map)]
fn handle_complete_transfer_token(
deps: DepsMut,
_env: Env,
@ -790,9 +799,9 @@ fn handle_complete_transfer_token(
relayer_address: &HumanAddr,
) -> StdResult<Response> {
let transfer_info = match transfer_type {
TransferType::WithoutPayload => TransferInfo::deserialize(&data)?,
TransferType::WithoutPayload => TransferInfo::deserialize(data)?,
TransferType::WithPayload { payload: _ } => {
TransferWithPayloadInfo::deserialize(&data)?.transfer_info
TransferWithPayloadInfo::deserialize(data)?.as_transfer_info()
}
};
@ -922,6 +931,7 @@ fn handle_complete_transfer_token(
}
}
#[allow(clippy::too_many_arguments)]
fn handle_complete_transfer_token_native(
deps: DepsMut,
_env: Env,
@ -934,9 +944,9 @@ fn handle_complete_transfer_token_native(
relayer_address: &HumanAddr,
) -> StdResult<Response> {
let transfer_info = match transfer_type {
TransferType::WithoutPayload => TransferInfo::deserialize(&data)?,
TransferType::WithoutPayload => TransferInfo::deserialize(data)?,
TransferType::WithPayload { payload: () } => {
TransferWithPayloadInfo::deserialize(&data)?.transfer_info
TransferWithPayloadInfo::deserialize(data)?.as_transfer_info()
}
};
@ -1000,6 +1010,7 @@ fn handle_complete_transfer_token_native(
.add_attribute("fee", fee.to_string()))
}
#[allow(clippy::too_many_arguments)]
fn handle_initiate_transfer(
deps: DepsMut,
env: Env,
@ -1039,6 +1050,7 @@ fn handle_initiate_transfer(
}
}
#[allow(clippy::too_many_arguments)]
fn handle_initiate_transfer_token(
deps: DepsMut,
env: Env,
@ -1067,6 +1079,10 @@ fn handle_initiate_transfer_token(
let mut messages: Vec<CosmosMsg> = vec![];
let mut submessages: Vec<SubMsg> = vec![];
// we'll only need this for payload 3 transfers
let sender_address = deps.api.addr_canonicalize(&info.sender.to_string())?;
let sender_address = extend_address_to_32_array(&sender_address);
match is_wrapped_asset_read(deps.storage).load(asset_canonical.as_slice()) {
Ok(_) => {
// If the fee is too large the user will receive nothing.
@ -1091,28 +1107,38 @@ fn handle_initiate_transfer_token(
asset_chain = wrapped_token_info.asset_chain;
asset_address = wrapped_token_info.asset_address.to_array()?;
let transfer_info = TransferInfo {
token_chain: asset_chain,
token_address: ExternalTokenId::from_foreign_token(asset_chain, asset_address),
amount: (0, amount.u128()),
recipient_chain,
recipient,
fee: (0, fee.u128()),
};
let external_id = ExternalTokenId::from_foreign_token(asset_chain, asset_address);
let token_bridge_message: TokenBridgeMessage = match transfer_type {
TransferType::WithoutPayload => TokenBridgeMessage {
action: Action::TRANSFER,
payload: transfer_info.serialize(),
},
TransferType::WithPayload { payload } => TokenBridgeMessage {
action: Action::TRANSFER_WITH_PAYLOAD,
payload: TransferWithPayloadInfo {
transfer_info,
payload,
TransferType::WithoutPayload => {
let transfer_info = TransferInfo {
amount: (0, amount.u128()),
token_address: external_id,
token_chain: asset_chain,
recipient,
recipient_chain,
fee: (0, fee.u128()),
};
TokenBridgeMessage {
action: Action::TRANSFER,
payload: transfer_info.serialize(),
}
.serialize(),
},
}
TransferType::WithPayload { payload } => {
let transfer_info = TransferWithPayloadInfo {
amount: (0, amount.u128()),
token_address: external_id,
token_chain: asset_chain,
recipient,
recipient_chain,
sender_address,
payload,
};
TokenBridgeMessage {
action: Action::TRANSFER_WITH_PAYLOAD,
payload: transfer_info.serialize(),
}
}
};
messages.push(CosmosMsg::Wasm(WasmMsg::Execute {
@ -1177,15 +1203,6 @@ fn handle_initiate_transfer_token(
amount = Uint128::new(amount.u128().checked_div(multiplier).unwrap());
fee = Uint128::new(fee.u128().checked_div(multiplier).unwrap());
let transfer_info = TransferInfo {
token_chain: asset_chain,
token_address: external_id,
amount: (0, amount.u128()),
recipient_chain,
recipient: recipient.clone(),
fee: (0, fee.u128()),
};
// Fetch current CW20 Balance pre-transfer.
let balance: BalanceResponse =
deps.querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
@ -1206,18 +1223,35 @@ fn handle_initiate_transfer_token(
assert!(wrapped_transfer_tmp(deps.storage).load().is_err());
let token_bridge_message: TokenBridgeMessage = match transfer_type {
TransferType::WithoutPayload => TokenBridgeMessage {
action: Action::TRANSFER,
payload: transfer_info.serialize(),
},
TransferType::WithPayload { payload } => TokenBridgeMessage {
action: Action::TRANSFER_WITH_PAYLOAD,
payload: TransferWithPayloadInfo {
transfer_info,
payload,
TransferType::WithoutPayload => {
let transfer_info = TransferInfo {
amount: (0, amount.u128()),
token_address: external_id,
token_chain: asset_chain,
recipient,
recipient_chain,
fee: (0, fee.u128()),
};
TokenBridgeMessage {
action: Action::TRANSFER,
payload: transfer_info.serialize(),
}
.serialize(),
},
}
TransferType::WithPayload { payload } => {
let transfer_info = TransferWithPayloadInfo {
amount: (0, amount.u128()),
token_address: external_id,
token_chain: asset_chain,
recipient,
recipient_chain,
sender_address,
payload,
};
TokenBridgeMessage {
action: Action::TRANSFER_WITH_PAYLOAD,
payload: transfer_info.serialize(),
}
}
};
let token_address = deps.api.addr_validate(&asset)?;
@ -1242,7 +1276,7 @@ fn handle_initiate_transfer_token(
.add_attribute(
"transfer.sender",
hex::encode(extend_address_to_32(
&deps.api.addr_canonicalize(&info.sender.as_str())?,
&deps.api.addr_canonicalize(info.sender.as_str())?,
)),
)
.add_attribute("transfer.recipient_chain", recipient_chain.to_string())
@ -1257,9 +1291,10 @@ fn format_native_denom_symbol(denom: &str) -> String {
return "LUNA".to_string();
}
//TODO: is there better formatting to do here?
denom.to_uppercase().to_string()
denom.to_uppercase()
}
#[allow(clippy::too_many_arguments)]
fn handle_initiate_transfer_native_token(
deps: DepsMut,
env: Env,
@ -1299,38 +1334,48 @@ fn handle_initiate_transfer_native_token(
send_native(deps.storage, &asset_address, amount)?;
let transfer_info = TransferInfo {
token_chain: asset_chain,
token_address: asset_address.clone(),
amount: (0, amount.u128()),
recipient_chain,
recipient: recipient.clone(),
fee: (0, fee.u128()),
};
let token_bridge_message: TokenBridgeMessage = match transfer_type {
TransferType::WithoutPayload => TokenBridgeMessage {
action: Action::TRANSFER,
payload: transfer_info.serialize(),
},
TransferType::WithPayload { payload } => TokenBridgeMessage {
action: Action::TRANSFER_WITH_PAYLOAD,
payload: TransferWithPayloadInfo {
transfer_info,
payload,
TransferType::WithoutPayload => {
let transfer_info = TransferInfo {
amount: (0, amount.u128()),
token_address: asset_address.clone(),
token_chain: asset_chain,
recipient,
recipient_chain,
fee: (0, fee.u128()),
};
TokenBridgeMessage {
action: Action::TRANSFER,
payload: transfer_info.serialize(),
}
.serialize(),
},
}
TransferType::WithPayload { payload } => {
let sender_address = deps.api.addr_canonicalize(&info.sender.to_string())?;
let sender_address = extend_address_to_32_array(&sender_address);
let transfer_info = TransferWithPayloadInfo {
amount: (0, amount.u128()),
token_address: asset_address.clone(),
token_chain: asset_chain,
recipient,
recipient_chain,
sender_address,
payload,
};
TokenBridgeMessage {
action: Action::TRANSFER_WITH_PAYLOAD,
payload: transfer_info.serialize(),
}
}
};
let sender = deps.api.addr_canonicalize(&info.sender.as_str())?;
let sender = deps.api.addr_canonicalize(info.sender.as_str())?;
messages.push(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: cfg.wormhole_contract,
msg: to_binary(&WormholeExecuteMsg::PostMessage {
message: Binary::from(token_bridge_message.serialize()),
nonce,
})?,
funds: info.funds.clone(),
funds: info.funds,
}));
Ok(Response::new()
@ -1372,7 +1417,7 @@ pub fn query_wrapped_registry(
address: &[u8],
) -> StdResult<WrappedRegistryResponse> {
// Check if this asset is already deployed
match wrapped_asset_read(deps.storage, chain).load(&address) {
match wrapped_asset_read(deps.storage, chain).load(address) {
Ok(address) => Ok(WrappedRegistryResponse {
address: address.into_string(),
}),
@ -1394,9 +1439,22 @@ fn query_transfer_info(deps: Deps, env: Env, vaa: &Binary) -> StdResult<Transfer
let message = TokenBridgeMessage::deserialize(&data)?;
match message.action {
Action::ATTEST_META => ContractError::InvalidVAAAction.std_err(),
_ => {
Action::TRANSFER => {
let core = TransferInfo::deserialize(&message.payload)?;
Ok(TransferInfoResponse {
amount: core.amount.1.into(),
token_address: core.token_address.serialize(),
token_chain: core.token_chain,
recipient: core.recipient,
recipient_chain: core.recipient_chain,
fee: core.fee.1.into(),
payload: vec![],
})
}
Action::TRANSFER_WITH_PAYLOAD => {
let info = TransferWithPayloadInfo::deserialize(&message.payload)?;
let core = info.transfer_info;
let core = info.as_transfer_info();
Ok(TransferInfoResponse {
amount: core.amount.1.into(),
@ -1408,9 +1466,10 @@ fn query_transfer_info(deps: Deps, env: Env, vaa: &Binary) -> StdResult<Transfer
payload: info.payload,
})
}
other => Err(StdError::generic_err(format!("Invalid action: {}", other))),
}
}
fn is_governance_emitter(cfg: &ConfigInfo, emitter_chain: u16, emitter_address: &Vec<u8>) -> bool {
cfg.gov_chain == emitter_chain && cfg.gov_address == emitter_address.clone()
fn is_governance_emitter(cfg: &ConfigInfo, emitter_chain: u16, emitter_address: &[u8]) -> bool {
cfg.gov_chain == emitter_chain && cfg.gov_address == emitter_address
}

View File

@ -250,30 +250,72 @@ impl TransferInfo {
// 64 u16 token_chain
// 66 [u8; 32] recipient
// 98 u16 recipient_chain
// 100 u256 fee
// 100 [u8; 32] sender_address
// 132 [u8] payload
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct TransferWithPayloadInfo {
pub transfer_info: TransferInfo,
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],
pub payload: Vec<u8>,
}
impl TransferWithPayloadInfo {
pub fn deserialize(data: &Vec<u8>) -> StdResult<Self> {
let transfer_info = TransferInfo::deserialize(data)?;
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);
let payload = TransferWithPayloadInfo::get_payload(data);
Ok(TransferWithPayloadInfo {
transfer_info,
amount,
token_address,
token_chain,
recipient,
recipient_chain,
sender_address,
payload,
})
}
pub fn serialize(&self) -> Vec<u8> {
[self.transfer_info.serialize(), self.payload.clone()].concat()
[
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()
}
pub fn get_payload(data: &Vec<u8>) -> Vec<u8> {
return data[132..].to_vec();
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),
}
}
}

View File

@ -141,15 +141,37 @@ fn deserialize_transfer_vaa() -> StdResult<()> {
#[test]
fn deserialize_transfer_with_payload_vaa() -> StdResult<()> {
// ┌──────────────────────────────────────────────────────────────────────────────┐
// │ Wormhole VAA v1 │ nonce: 2080370133 │ time: 0 │
// │ guardian set #0 │ #4568529024235897313 │ consistency: 32 │
// ├──────────────────────────────────────────────────────────────────────────────┤
// │ Signature: │
// │ #0: 2565e7ae10421624fd81118855acda893e752aeeef31c13fbfc417591ada... │
// ├──────────────────────────────────────────────────────────────────────────────┤
// │ Emitter: 11111111111111111111111111111115 (Solana) │
// ╞══════════════════════════════════════════════════════════════════════════════╡
// │ Token transfer with payload (aka payload 3) │
// │ Amount: 1.0 │
// │ Token: terra1qqqqqqqqqqqqqqqqqqqqqqqqqp6h2umyswfh6y (Terra) │
// │ Recipient: terra13nkgqrfymug724h8pprpexqj9h629sa3ncw7sh (Terra) │
// │ From: 1399a4e782b935d2bb36b97586d3df8747b07dc66902d807eed0ae99e00ed256 │
// ╞══════════════════════════════════════════════════════════════════════════════╡
// │ Custom payload: │
// │ Length: 30 (0x1e) bytes │
// │ 0000: 41 6c 6c 20 79 6f 75 72 20 62 61 73 65 20 61 72 All your base ar│
// │ 0010: 65 20 62 65 6c 6f 6e 67 20 74 6f 20 75 73 e belong to us │
// └──────────────────────────────────────────────────────────────────────────────┘
let signed_vaa = "\
010000000001002b0e392ebe370e718b91dcafbba21094efd8e7f1f12e28bd90\
a178b4dfbbc708675152a3cd2edd20e8e018600026b73b6c6cbf02622903409e\
8b48ab7fa30ef001000000010000000100010000000000000000000000000000\
00000000000000000000000000000000ffff0000000000000002000300000000\
00000000000000000000000000000000000000000000000005f5e10001000000\
010000000001002565e7ae10421624fd81118855acda893e752aeeef31c13fbf\
c417591ada039822195a1321a72cc4bac1c6031e0595f1c1361ca2a30d941a41\
95fad8020d43d500000000007bffedd500010000000000000000000000000000\
0000000000000000000000000000000000043f66acf143a481e1200300000000\
00000000000000000000000000000000000000000000000005f5e10000000000\
0000000000000000000000000000000000000000000000007575736400030000\
000000000000000000008cec800d24df11e556e708461c98122df4a2c3b10003\
00000000000000000000000000000000000000000000000000000000000f4240\
1399a4e782b935d2bb36b97586d3df8747b07dc66902d807eed0ae99e00ed256\
416c6c20796f75722062617365206172652062656c6f6e6720746f207573";
let signed_vaa = hex::decode(signed_vaa).unwrap();
@ -161,13 +183,12 @@ fn deserialize_transfer_with_payload_vaa() -> StdResult<()> {
"message.action != expected"
);
let info_with_payload = TransferWithPayloadInfo::deserialize(&message.payload)?;
let info = info_with_payload.transfer_info;
let info = TransferWithPayloadInfo::deserialize(&message.payload)?;
let amount = (0u128, 100_000_000u128);
assert_eq!(info.amount, amount, "info.amount != expected");
let token_address = "0100000000000000000000000000000000000000000000000000000075757364";
let token_address = "0000000000000000000000000000000000000000000000000000000075757364";
let token_address = hex::decode(token_address).unwrap();
assert_eq!(
info.token_address.serialize().to_vec(),
@ -189,19 +210,25 @@ fn deserialize_transfer_with_payload_vaa() -> StdResult<()> {
"info.recipient != expected"
);
let sender = "1399a4e782b935d2bb36b97586d3df8747b07dc66902d807eed0ae99e00ed256";
let sender = hex::decode(sender).unwrap();
assert_eq!(
info.sender_address.to_vec(),
sender,
"info.sender != expected"
);
let recipient_chain = 3u16;
assert_eq!(
info.recipient_chain, recipient_chain,
"info.recipient_chain != expected"
);
let fee = (0u128, 1_000_000u128);
assert_eq!(info.fee, fee, "info.fee != expected");
let transfer_payload = "All your base are belong to us";
let transfer_payload = transfer_payload.as_bytes();
assert_eq!(
info_with_payload.payload.as_slice(),
info.payload.as_slice(),
transfer_payload,
"info.payload != expected"
);

View File

@ -1,4 +1,5 @@
import {
getEmitterAddressTerra,
parseSequenceFromLogTerra,
setDefaultWasm,
} from "@certusone/wormhole-sdk";
@ -539,7 +540,7 @@ describe("Bridge Tests", () => {
// need to deposit before initiating transfer
const deposit = new MsgExecuteContract(
wallet.key.accAddress,
walletAddress,
tokenBridge,
{
deposit_tokens: {},
@ -565,7 +566,7 @@ describe("Bridge Tests", () => {
"base64"
),
fee: relayerFee,
payload: Buffer.from(myPayload, "hex").toString("base64"),
payload: Buffer.from(myPayload, "ascii").toString("base64"),
nonce: 69,
},
}
@ -584,6 +585,61 @@ describe("Bridge Tests", () => {
initiateTransferWithPayload,
]);
console.log(receipt);
const jsonLog = JSON.parse(receipt.raw_log);
let message = "";
jsonLog.map((row: any) => {
row.events.map((event: any) => {
event.attributes.map((attribute: any) => {
if (attribute.key === "message.message") {
message = attribute.value;
}
});
});
});
// payload type
let last = 0;
let len = 2;
expect(message.substring(last, last + len)).toEqual("03");
last += len;
// amount
len = 64;
expect(message.substring(last, last + len)).toEqual(
"0000000000000000000000000000000000000000000000000000000005f5e100"
);
last += len;
// token address
len = 64;
expect(message.substring(last, last + len)).toEqual(
"01fa6c6fbc36d8c245b0a852a43eb5d644e8b4c477b27bfab9537c10945939da"
);
last += len;
// token chain
len = 4;
expect(message.substring(last, last + len)).toEqual("0012");
last += len;
// recipient address
len = 64;
expect(message.substring(last, last + len)).toEqual(
"0000000000000000000000004206942069420694206942069420694206942069"
);
last += len;
// recipient chain
len = 4;
expect(message.substring(last, last + len)).toEqual("0002");
last += len;
// sender address
len = 64;
expect(message.substring(last, last + len)).toEqual(
await getEmitterAddressTerra(walletAddress)
);
last += len;
// payload
expect(message.substring(last)).toEqual(
Buffer.from(myPayload, "ascii").toString("hex")
);
const balanceAfter = await getNativeBalance(client, tokenBridge, denom);
expect(balanceBefore.add(amount).eq(balanceAfter)).toBeTruthy();
@ -617,7 +673,7 @@ describe("Bridge Tests", () => {
LUNA_ADDRESS,
encodedTo,
CHAIN_ID,
relayerFee,
relayerFee, // now sender_address
additionalPayload
);
@ -638,11 +694,6 @@ describe("Bridge Tests", () => {
);
// check balances before execute
const walletBalanceBefore = await getNativeBalance(
client,
walletAddress,
denom
);
const contractBalanceBefore = await getNativeBalance(
client,
mockBridgeIntegration,
@ -667,33 +718,13 @@ describe("Bridge Tests", () => {
// execute outbound transfer with signed vaa
const receipt = await transactWithoutMemo(client, wallet, [submitVaa]);
// check wallet (relayer) balance change
const walletBalanceAfter = await getNativeBalance(
client,
walletAddress,
denom
);
const gasPaid = computeGasPaid(receipt);
const walletExpectedChange = new Int(relayerFee).sub(gasPaid);
// due to rounding, we should expect the balances to reconcile
// within 1 unit (equivalent to 1e-6 uluna). Best-case scenario
// we end up with slightly more balance than expected
const reconciled = walletBalanceAfter
.minus(walletExpectedChange)
.minus(walletBalanceBefore);
expect(
reconciled.greaterThanOrEqualTo("0") &&
reconciled.lessThanOrEqualTo("1")
).toBeTruthy();
// check contract balance change
const contractBalanceAfter = await getNativeBalance(
client,
mockBridgeIntegration,
denom
);
const contractExpectedChange = new Int(amount).sub(relayerFee);
const contractExpectedChange = new Int(amount);
expect(
contractBalanceBefore
.add(contractExpectedChange)