use crate::{Parameterize, Token, Tokenizable};
use fuels_types::errors::Error;
use fuels_types::param_types::ParamType;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct Bits256(pub [u8; 32]);
impl Bits256 {
pub fn from_hex_str(hex: &str) -> Result<Self, Error> {
let hex = if let Some(stripped_hex) = hex.strip_prefix("0x") {
stripped_hex
} else {
hex
};
let mut bytes = [0u8; 32];
hex::decode_to_slice(hex, &mut bytes as &mut [u8]).map_err(|e| {
Error::InvalidData(format!("Could not convert hex str '{hex}' to Bits256! {e}"))
})?;
Ok(Bits256(bytes))
}
}
impl Parameterize for Bits256 {
fn param_type() -> ParamType {
ParamType::B256
}
}
impl Tokenizable for Bits256 {
fn from_token(token: Token) -> Result<Self, Error>
where
Self: Sized,
{
match token {
Token::B256(data) => Ok(Bits256(data)),
_ => Err(Error::InvalidData(format!(
"Bits256 cannot be constructed from token {token}"
))),
}
}
fn into_token(self) -> Token {
Token::B256(self.0)
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct B512 {
bytes: [Bits256; 2],
}
impl From<(Bits256, Bits256)> for B512 {
fn from(bits_tuple: (Bits256, Bits256)) -> Self {
B512 {
bytes: [bits_tuple.0, bits_tuple.1],
}
}
}
impl Parameterize for B512 {
fn param_type() -> ParamType {
ParamType::Struct {
fields: vec![<[Bits256; 2usize]>::param_type()],
generics: vec![],
}
}
}
impl Tokenizable for B512 {
fn from_token(token: Token) -> Result<Self, Error>
where
Self: Sized,
{
if let Token::Struct(tokens) = token {
if let [Token::Array(data)] = tokens.as_slice() {
Ok(B512 {
bytes: <[Bits256; 2usize]>::from_token(Token::Array(data.to_vec()))?,
})
} else {
Err(Error::InstantiationError(format!(
"B512 expected one `Token::Array`, got {tokens:?}",
)))
}
} else {
Err(Error::InstantiationError(format!(
"B512 expected `Token::Struct`, got {token:?}",
)))
}
}
fn into_token(self) -> Token {
Token::Struct(vec![self.bytes.into_token()])
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct EvmAddress {
value: Bits256,
}
impl EvmAddress {
fn clear_12_bytes(bytes: [u8; 32]) -> [u8; 32] {
let mut bytes = bytes;
bytes[..12].copy_from_slice(&[0u8; 12]);
bytes
}
}
impl From<Bits256> for EvmAddress {
fn from(b256: Bits256) -> Self {
let value = Bits256(Self::clear_12_bytes(b256.0));
Self { value }
}
}
impl Parameterize for EvmAddress {
fn param_type() -> ParamType {
ParamType::Struct {
fields: vec![ParamType::B256],
generics: vec![],
}
}
}
impl Tokenizable for EvmAddress {
fn from_token(token: Token) -> Result<Self, Error>
where
Self: Sized,
{
if let Token::Struct(tokens) = token {
if let [Token::B256(data)] = tokens.as_slice() {
Ok(EvmAddress::from(Bits256(*data)))
} else {
Err(Error::InstantiationError(format!(
"EvmAddress expected one `Token::B256`, got {tokens:?}",
)))
}
} else {
Err(Error::InstantiationError(format!(
"EvmAddress expected `Token::Struct` got {token:?}",
)))
}
}
fn into_token(self) -> Token {
Token::Struct(vec![Bits256(self.value.0).into_token()])
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Tokenizable;
use fuels_types::param_types::ParamType;
#[test]
fn test_param_type_b256() {
assert_eq!(Bits256::param_type(), ParamType::B256);
}
#[test]
fn test_from_token_b256() -> Result<(), Error> {
let data = [1u8; 32];
let token = Token::B256(data);
let bits256 = Bits256::from_token(token)?;
assert_eq!(bits256.0, data);
Ok(())
}
#[test]
fn test_into_token_b256() {
let data = [1u8; 32];
let bits256 = Bits256(data);
let token = bits256.into_token();
assert_eq!(token, Token::B256(data));
}
#[test]
fn from_hex_str_b256() -> Result<(), Error> {
let hex_str = "0101010101010101010101010101010101010101010101010101010101010101";
let bits256 = Bits256::from_hex_str(hex_str)?;
assert_eq!(bits256.0, [1u8; 32]);
let hex_str = "0x0101010101010101010101010101010101010101010101010101010101010101";
let bits256 = Bits256::from_hex_str(hex_str)?;
assert_eq!(bits256.0, [1u8; 32]);
Ok(())
}
#[test]
fn test_param_type_evm_addr() {
assert_eq!(
EvmAddress::param_type(),
ParamType::Struct {
fields: vec![ParamType::B256],
generics: vec![]
}
);
}
#[test]
fn test_from_token_evm_addr() -> Result<(), Error> {
let data = [1u8; 32];
let token = Token::Struct(vec![Token::B256(data)]);
let evm_address = EvmAddress::from_token(token)?;
let expected_data = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1,
];
assert_eq!(evm_address.value.0, expected_data);
Ok(())
}
#[test]
fn test_into_token_evm_addr() {
let data = [1u8; 32];
let evm_address = EvmAddress::from(Bits256(data));
let token = evm_address.into_token();
let expected_data = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1,
];
assert_eq!(token, Token::Struct(vec![Token::B256(expected_data)]));
}
}