Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[r2r] validate input_tx is calling 'receiverSpend' in extract_secret #1596

Merged
merged 4 commits into from
Jan 4, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions mm2src/coins/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use ethkey::{sign, verify_address};
use futures::compat::Future01CompatExt;
use futures::future::{join_all, select, Either, FutureExt, TryFutureExt};
use futures01::Future;
use hex::encode;
use http::StatusCode;
use mm2_core::mm_ctx::{MmArc, MmWeak};
use mm2_err_handle::prelude::*;
Expand Down Expand Up @@ -127,6 +128,10 @@ const GAS_PRICE_APPROXIMATION_PERCENT_ON_TRADE_PREIMAGE: u64 = 7;
/// Lifetime of generated signed message for gui-auth requests
const GUI_AUTH_SIGNED_MESSAGE_LIFETIME_SEC: i64 = 90;

/// recieverSpend contract call bytes signature.
/// https://www.4byte.directory/signatures/?bytes4_signature=02ed292b.
const RECEIVERSPEND_BYTES_SIGNATURE: &str = "02ed292b";

lazy_static! {
pub static ref SWAP_CONTRACT: Contract = Contract::load(SWAP_CONTRACT_ABI.as_bytes()).unwrap();
pub static ref ERC20_CONTRACT: Contract = Contract::load(ERC20_ABI.as_bytes()).unwrap();
Expand Down Expand Up @@ -1135,6 +1140,16 @@ impl SwapOps for EthCoin {
async fn extract_secret(&self, _secret_hash: &[u8], spend_tx: &[u8]) -> Result<Vec<u8>, String> {
let unverified: UnverifiedTransaction = try_s!(rlp::decode(spend_tx));
let function = try_s!(SWAP_CONTRACT.function("receiverSpend"));

// Validate contract call; expected to be receiverSpend (02ed292b).
if unverified.data[0..4] != function.short_signature() {
return ERR!(
"Expected 'receiverSpend' contract call signature: {}, found {}",
RECEIVERSPEND_BYTES_SIGNATURE,
sergeyboyko0791 marked this conversation as resolved.
Show resolved Hide resolved
encode(&unverified.data[0..4])
);
};

let tokens = try_s!(function.decode_input(&unverified.data));
if tokens.len() < 3 {
return ERR!("Invalid arguments in 'receiverSpend' call: {:?}", tokens);
Expand Down
26 changes: 23 additions & 3 deletions mm2src/coins/eth/eth_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1405,7 +1405,7 @@ fn test_eth_extract_secret() {
}));

// raw transaction bytes of https://ropsten.etherscan.io/tx/0xcb7c14d3ff309996d582400369393b6fa42314c52245115d4a3f77f072c36da9
let tx_hex = &[
let tx_bytes = &[
249, 1, 9, 37, 132, 119, 53, 148, 0, 131, 2, 73, 240, 148, 123, 193, 187, 221, 106, 10, 114, 47, 201, 191, 252,
73, 201, 33, 182, 133, 236, 184, 75, 148, 128, 184, 164, 2, 237, 41, 43, 188, 96, 248, 252, 165, 132, 81, 30,
243, 34, 85, 165, 46, 224, 176, 90, 137, 30, 19, 123, 224, 67, 83, 53, 74, 57, 148, 140, 95, 45, 70, 147, 0, 0,
Expand All @@ -1418,13 +1418,33 @@ fn test_eth_extract_secret() {
100, 189, 72, 74, 221, 144, 66, 170, 68, 121, 29, 105, 19, 194, 35, 245, 196, 131, 236, 29, 105, 101, 30,
];

let secret = block_on(coin.extract_secret(&[0u8; 20], tx_hex.as_slice()));
let secret = block_on(coin.extract_secret(&[0u8; 20], tx_bytes.as_slice()));
assert!(secret.is_ok());
let expect_secret = &[
168, 151, 11, 232, 224, 253, 63, 180, 26, 114, 23, 184, 27, 10, 161, 80, 178, 251, 73, 204, 80, 174, 97, 118,
149, 204, 186, 187, 243, 185, 19, 128,
];
assert_eq!(expect_secret.as_slice(), &secret.unwrap())
assert_eq!(expect_secret.as_slice(), &secret.unwrap());

// Test for unexpected contract signature
// raw transaction bytes of ethPayment contract https://etherscan
// .io/tx/0x0869be3e5d4456a29d488a533ad6c118620fef450f36778aecf31d356ff8b41f
let tx_bytes = [
248, 240, 3, 133, 1, 42, 5, 242, 0, 131, 2, 73, 240, 148, 133, 0, 175, 192, 188, 82, 20, 114, 128, 130, 22, 51,
38, 194, 255, 12, 115, 244, 168, 113, 135, 110, 205, 245, 24, 127, 34, 254, 184, 132, 21, 44, 243, 175, 73, 33,
143, 82, 117, 16, 110, 27, 133, 82, 200, 114, 233, 42, 140, 198, 35, 21, 201, 249, 187, 180, 20, 46, 148, 40,
9, 228, 193, 130, 71, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 152, 41, 132, 9, 201, 73, 19, 94, 237, 137, 35,
61, 4, 194, 207, 239, 152, 75, 175, 245, 157, 174, 10, 214, 161, 207, 67, 70, 87, 246, 231, 212, 47, 216, 119,
68, 237, 197, 125, 141, 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, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 72, 125, 102, 28, 159, 180, 237, 198, 97, 87, 80, 82, 200, 104, 40, 245,
221, 7, 28, 122, 104, 91, 99, 1, 159, 140, 25, 131, 101, 74, 87, 50, 168, 146, 187, 90, 160, 51, 1, 123, 247,
6, 108, 165, 181, 188, 40, 56, 47, 211, 229, 221, 73, 5, 15, 89, 81, 117, 225, 216, 108, 98, 226, 119, 232, 94,
184, 42, 106,
];
let secret = block_on(coin.extract_secret(&[0u8; 20], tx_bytes.as_slice()))
.err()
.unwrap();
assert!(secret.contains("Expected 'receiverSpend' contract call signature"));
}

#[test]
Expand Down