I have a weird issue. I'm trying to keccak256 packed encoded arguments in Rust [which should mimic Soldity's behavior to be checked on chain later]. I've failed for now. To figure out the issue I've been writing a small test contract with the following functions:
function doKeccak(bytes memory _data) public pure returns (bytes32) {
return keccak256(_data);
}
function packed(
address _from,
address _to,
uint256 _value,
bytes memory _data,
uint256 _nonce,
uint256 _gasPrice,
uint256 _gasLimit
) public pure returns (bytes memory) {
return
abi.encodePacked(
bytes1(0x19),
bytes1(0),
_from,
_to,
_value,
_data,
_nonce,
_gasPrice,
_gasLimit
);
}
function doKeccakPacked(
address _from,
address _to,
uint256 _value,
bytes memory _data,
uint256 _nonce,
uint256 _gasPrice,
uint256 _gasLimit
) public pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
bytes1(0x19),
bytes1(0),
_from,
_to,
_value,
_data,
_nonce,
_gasPrice,
_gasLimit
)
);
}
Now, from the rust program if I call [pseudo-code] contract.doKeccakPacked(args..)
and contract.doKeccak(contract.packed(args))
I get different results ...
Any idea ?
Edit Here is, for instance, a raw Rust params array, which leads to different results:
[
Address(
0xdfa1468d07fc86840a6eb53e0e65cebde81d1af9,
),
Address(
0x7f114fc87edc5f1311d4e77d1a3018a3dc34f47e,
),
Uint(
0,
),
Bytes(
[
201,
13,
180,
71,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
127,
17,
79,
200,
126,
220,
95,
19,
17,
212,
231,
125,
26,
48,
24,
163,
220,
52,
244,
126,
],
),
Uint(
94481061581245121,
),
Uint(
0,
),
Uint(
250000,
),
]
Edit 2
Here is the rust code:
fn hash_sign(
&self,
wallet: Address,
data: ethabi::Bytes,
nonce: U256,
) -> Result<Bytes, String> {
let options = Options::default();
// this is the contract whose test functions are above
let erc_1077_hash_abi = ethabi::Contract::load(constants::abis::ERC1077_HASH).unwrap();
let erc_1077_hash_address = Address::from_str(&"83649266Ba0a8CAd860403a6532F12c6074BBDAC").unwrap();
let function = erc_1077_hash_abi.function("doKeccakPacked").unwrap();
let params: [ethabi::Token; 7] = [
ethabi::Token::Address(self.address),
ethabi::Token::Address(wallet),
ethabi::Token::Uint(self.value()),
ethabi::Token::Bytes(data.clone()),
ethabi::Token::Uint(nonce),
ethabi::Token::Uint(self.gas_price()),
ethabi::Token::Uint(self.gas_limit()),
];
let encoded = function.encode_input(¶ms).unwrap();
let result_1 = self.web3.eth().call(
CallRequest {
from: None,
to: erc_1077_hash_address,
gas: options.gas,
gas_price: options.gas_price,
value: options.value,
data: Some(Bytes(encoded)),
},
None.into(),
);
let result_1 = match result_1.wait() {
Ok(s) => Ok(s),
Err(_e) => Err(format!("error")),
};
let function = erc_1077_hash_abi.function("packed").unwrap();
let encoded = function.encode_input(¶ms).unwrap();
let packed = self.web3.eth().call(
CallRequest {
from: None,
to: erc_1077_hash_address,
gas: options.gas,
gas_price: options.gas_price,
value: options.value,
data: Some(Bytes(encoded.clone())),
},
None.into(),
);
let packed = packed.wait().unwrap();
let packed = packed.0;
let function = erc_1077_hash_abi.function("doKeccak").unwrap();
let params: [ethabi::Token; 1] = [
ethabi::Token::Bytes(packed),
];
let encoded = function.encode_input(¶ms).unwrap();
let result_2 = self.web3.eth().call(
CallRequest {
from: None,
to: erc_1077_hash_address,
gas: options.gas,
gas_price: options.gas_price,
value: options.value,
data: Some(Bytes(encoded)),
},
None.into(),
);
let result_2 = match result_2.wait() {
Ok(s) => Ok(s),
Err(_e) => Err(format!("error")),
};
result_1
}
Here result_1 and result_2 are differents ...
x19
does not compile.packed
is not a function.set
to andfrom
to whatever - different - addresses you want,gasPrice
to 0,gasLimit
to 250000,nonce
to 35681459843,value
to 0 and data to whatever bytes array. Thanks for helping!