use crate::bindings::i_universal_router_commands::IUniversalRouterCommandsCalls;
macro_rules! no_variants {
() => {
0x07 | 0x0e | 0x0f | 0x1e | 0x1f
};
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
pub enum Command {
#[default]
V3SwapExactIn = 0x00,
V3SwapExactOut,
Permit2TransferFrom,
Permit2PermitBatch,
Sweep,
Transfer,
PayPortion,
V2SwapExactIn = 0x08,
V2SwapExactOut,
Permit2Permit,
WrapEth,
UnwrapEth,
Permit2TransferFromBatch,
Seaport = 0x10,
LooksRare721,
Nftx,
CryptoPunks,
LooksRare1155,
OwnerCheck721,
OwnerCheck1155,
SweepErc721,
X2y2721 = 0x18,
SudoSwap,
Nft20,
X2y21155,
Foundation,
SweepErc1155,
Invalid = 0x80,
}
impl From<&IUniversalRouterCommandsCalls> for Command {
fn from(value: &IUniversalRouterCommandsCalls) -> Self {
use IUniversalRouterCommandsCalls::*;
match value {
V3SwapExactIn(_) => Self::V3SwapExactIn,
V3SwapExactOut(_) => Self::V3SwapExactOut,
Permit2TransferFrom(_) => Self::Permit2TransferFrom,
Permit2PermitBatch(_) => Self::Permit2PermitBatch,
Sweep(_) => Self::Sweep,
Transfer(_) => Self::Transfer,
PayPortion(_) => Self::PayPortion,
V2SwapExactIn(_) => Self::V2SwapExactIn,
V2SwapExactOut(_) => Self::V2SwapExactOut,
Permit2Permit(_) => Self::Permit2Permit,
WrapEth(_) => Self::WrapEth,
UnwrapEth(_) => Self::UnwrapEth,
Permit2TransferFromBatch(_) => Self::Permit2TransferFromBatch,
Seaport(_) => Self::Seaport,
LooksRare721(_) => Self::LooksRare721,
Nftx(_) => Self::Nftx,
CryptoPunks(_) => Self::CryptoPunks,
LooksRare1155(_) => Self::LooksRare1155,
OwnerCheck721(_) => Self::OwnerCheck721,
OwnerCheck1155(_) => Self::OwnerCheck1155,
SweepErc721(_) => Self::SweepErc721,
X2Y2721(_) => Self::X2y2721,
SudoSwap(_) => Self::SudoSwap,
Nft20(_) => Self::Nft20,
X2Y21155(_) => Self::X2y21155,
Foundation(_) => Self::Foundation,
SweepErc1155(_) => Self::SweepErc1155,
}
}
}
impl From<IUniversalRouterCommandsCalls> for Command {
fn from(value: IUniversalRouterCommandsCalls) -> Self {
From::from(&value)
}
}
impl Command {
pub const MASK: u8 = 0b00011111;
pub const UNUSED_BITS: u8 = 0b01100000;
pub const FLAG_ALLOW_REVERT: u8 = 0b10000000;
pub const NFT_TYPE_MASK: u8 = 0b00010000;
pub const SUB_IF_BRANCH_MASK: u8 = 0b00001000;
pub fn encode(self, allow_revert: bool) -> u8 {
(self as u8 & Self::MASK) | ((allow_revert as u8) << 7)
}
pub fn decode(byte: u8) -> (Self, bool) {
let allow_revert = (byte >> 7) == 1;
const MAX: u8 = Command::MASK + 1;
let command = match byte {
no_variants!() => Self::Invalid,
MAX.. => Self::Invalid,
_ => unsafe { std::mem::transmute(byte) },
};
(command, allow_revert)
}
#[allow(clippy::match_like_matches_macro)]
pub const fn is_valid(&self) -> bool {
match self {
Self::Invalid => false,
_ => true,
}
}
#[allow(clippy::match_like_matches_macro)]
pub const fn is_invalid(&self) -> bool {
match self {
Self::Invalid => true,
_ => false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_command_encoding() {
for byte in 0..=u8::MAX {
let allow_revert = (byte >> 7) == 1;
let (command, r_allow_revert) = Command::decode(byte);
assert_eq!(r_allow_revert, allow_revert);
const MAX: u8 = Command::MASK + 1;
match byte {
no_variants!() => assert_eq!(command, Command::Invalid),
MAX.. => assert_eq!(command, Command::Invalid),
_ => {
assert_ne!(command, Command::Invalid);
assert_eq!(command.encode(allow_revert), byte & !Command::UNUSED_BITS);
let _s = format!("0x{byte:02x} => {command:?}");
}
};
}
}
}