use crate::{keccak, Address, Sig, Word, U256};
use k256::ecdsa::SigningKey;
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct Authorization {
pub authorizer: Address,
pub authorized: Address,
pub is_authorized: bool,
pub nonce: U256,
pub deadline: U256,
}
impl Authorization {
pub fn new(
authorizer: Address,
authorized: Address,
is_authorized: bool,
nonce: U256,
deadline: U256,
) -> Self {
Authorization {
authorizer,
authorized,
is_authorized,
nonce,
deadline,
}
}
}
pub const AUTHORIZATION_TYPE: &str =
"Authorization(address authorizer,address authorized,bool isAuthorized,uint256 nonce,uint256 deadline)";
pub const AUTHORIZATION_TYPEHASH: Word = [
0x81, 0xd0, 0x28, 0x4f, 0xb0, 0xe2, 0xcd, 0xe1, 0x8d, 0x05, 0x53, 0xb0, 0x61, 0x89, 0xd6, 0xf7,
0x61, 0x3c, 0x96, 0xa0, 0x1b, 0xb5, 0xb5, 0xe7, 0x82, 0x8e, 0xad, 0xe6, 0xa0, 0xdc, 0xac, 0x91,
];
pub const AUTHORIZE_DOMAIN_TYPE: &str = "EIP712Domain(uint256 chainId,address verifyingContract)";
pub fn authorization_typehash() -> Word {
keccak(AUTHORIZATION_TYPE.as_bytes())
}
#[inline]
fn addr_word(a: &Address) -> Word {
let mut w = [0u8; 32];
w[12..].copy_from_slice(a);
w
}
#[inline]
fn bool_word(b: bool) -> Word {
let mut w = [0u8; 32];
w[31] = b as u8;
w
}
fn encode(words: &[Word]) -> Vec<u8> {
let mut out = Vec::with_capacity(words.len() * 32);
for w in words {
out.extend_from_slice(w);
}
out
}
pub fn hash_authorization(a: &Authorization) -> Word {
keccak(&encode(&[
AUTHORIZATION_TYPEHASH,
addr_word(&a.authorizer),
addr_word(&a.authorized),
bool_word(a.is_authorized),
a.nonce.to_be_bytes::<32>(),
a.deadline.to_be_bytes::<32>(),
]))
}
pub fn authorize_domain_separator(chain_id: Word, authorizer_contract: &Address) -> Word {
keccak(&encode(&[
keccak(AUTHORIZE_DOMAIN_TYPE.as_bytes()),
chain_id,
addr_word(authorizer_contract),
]))
}
pub fn authorization_digest(
a: &Authorization,
chain_id: Word,
authorizer_contract: &Address,
) -> Word {
let hash_struct = hash_authorization(a);
let domain_separator = authorize_domain_separator(chain_id, authorizer_contract);
let mut buf = Vec::with_capacity(2 + 64);
buf.extend_from_slice(&[0x19, 0x01]);
buf.extend_from_slice(&domain_separator);
buf.extend_from_slice(&hash_struct);
keccak(&buf)
}
pub fn sign_authorization(
sk: &SigningKey,
a: &Authorization,
chain_id: Word,
authorizer_contract: &Address,
) -> Sig {
crate::sign_digest(sk, &authorization_digest(a, chain_id, authorizer_contract))
}
pub fn recover_authorization(
a: &Authorization,
chain_id: Word,
authorizer_contract: &Address,
sig: &Sig,
) -> Option<Address> {
crate::recover(&authorization_digest(a, chain_id, authorizer_contract), sig)
}