use crate::utils::address::Address;
use crate::utils::hex;
use crate::utils::json::Json;
use crate::utils::sign::eip712::word::{address_word, uint256, word, word_decimal};
use crate::utils::sign::keccak::{Keccak256, keccak256};
use crate::utils::sign::msgpack::Value;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Field<'a> {
String(&'a str),
Address(Address),
Uint64(u64),
Bytes32([u8; 32]),
Bool(bool),
Uint32(u32),
Uint128(u128),
Uint256([u8; 32]),
Uint256Array(&'a [[u8; 32]]),
}
impl Field<'_> {
#[must_use]
pub const fn solidity_type(&self) -> &'static str {
match self {
Field::String(_) => "string",
Field::Address(_) => "address",
Field::Uint64(_) => "uint64",
Field::Bytes32(_) => "bytes32",
Field::Bool(_) => "bool",
Field::Uint32(_) => "uint32",
Field::Uint128(_) => "uint128",
Field::Uint256(_) => "uint256",
Field::Uint256Array(_) => "uint256[]",
}
}
#[must_use]
pub fn encode(&self) -> [u8; 32] {
match self {
Field::String(text) => keccak256(text.as_bytes()),
Field::Address(address) => address_word(*address),
Field::Uint64(number) => word(*number),
Field::Bytes32(bytes) | Field::Uint256(bytes) => *bytes,
Field::Bool(value) => word(u64::from(*value)),
Field::Uint32(number) => word(u64::from(*number)),
Field::Uint128(number) => uint256(*number),
Field::Uint256Array(words) => {
words.iter().fold(Keccak256::new(), |sponge, element| sponge.chain(element)).finalize()
}
}
}
#[must_use]
pub fn to_json(&self) -> Json {
match self {
Field::String(text) => Json::String((*text).to_owned()),
Field::Address(address) => Json::String(address.to_hex()),
Field::Uint64(number) => Json::Number(number.to_string()),
Field::Bytes32(bytes) => Json::String(hex::encode_prefixed(bytes)),
Field::Bool(value) => Json::Bool(*value),
Field::Uint32(number) => Json::Number(number.to_string()),
Field::Uint128(number) => Json::String(number.to_string()),
Field::Uint256(bytes) => Json::String(word_decimal(bytes)),
Field::Uint256Array(words) => {
Json::Array(words.iter().map(|element| Json::String(word_decimal(element))).collect())
}
}
}
#[must_use]
pub fn to_wire(&self) -> Value {
match self {
Field::String(text) => Value::from((*text).to_owned()),
Field::Address(address) => Value::from(address.to_hex()),
Field::Uint64(number) => Value::Uint(*number),
Field::Bytes32(bytes) => Value::from(hex::encode_prefixed(bytes)),
Field::Bool(value) => Value::Bool(*value),
Field::Uint32(number) => Value::Uint(u64::from(*number)),
Field::Uint128(number) => Value::from(number.to_string()),
Field::Uint256(bytes) => Value::from(word_decimal(bytes)),
Field::Uint256Array(words) => {
Value::Array(words.iter().map(|element| Value::from(word_decimal(element))).collect())
}
}
}
}
#[cfg(test)]
#[path = "tests/field.rs"]
mod tests;