use fuels::{
core::{
codec::calldata,
traits::Tokenizable,
},
crypto::Message,
types::{
Bits256,
ChainId,
Identity,
},
};
use crate::{
trade_account::{
generate_session_signing_payload,
generate_signing_payload,
},
trade_account_deploy::{
CallContractArg,
CallContractArgs as TradeAccountCallContractArgs,
CallParams,
Domain,
EIP712Domain,
Encoding,
MultiCallContractArgs,
RevokeArgs,
SRC16Domain,
Secp256k1,
SessionArgs,
SetProxyTargetArgs,
Signature,
WithdrawArgs,
},
};
use ethers_core::{
types::{
H160,
RecoveryMessage,
Signature as EthSig,
U256,
U256 as Ethers256,
transaction::eip712::EIP712Domain as EVMDomain,
},
utils::keccak256,
};
const EVM_ADDRESS_PADDING_LENGTH: usize = 12;
fn fuel_contract_id_to_evm_address(id: [u8; 32]) -> [u8; 20] {
let mut addr = [0u8; 20];
addr.copy_from_slice(&id[12..32]);
addr
}
pub trait DomainExt {
fn separator(&self) -> [u8; 32];
fn encode<T>(&self, struct_type: T) -> [u8; 32]
where
T: SRC16Encode;
}
impl DomainExt for Domain {
fn separator(&self) -> [u8; 32] {
match self {
Domain::EIP712Domain(d) => EVMDomain::from(d.clone()).separator(),
Domain::SRC16Domain(d) => d.separator(),
}
}
fn encode<T>(&self, struct_type: T) -> [u8; 32]
where
T: SRC16Encode,
{
let ds = self.separator();
let encoding = match self {
Domain::SRC16Domain(_) => Encoding::SRC16,
Domain::EIP712Domain(_) => Encoding::EIP712,
};
let sh = struct_type.struct_hash(encoding);
let mut preimage = Vec::with_capacity(2 + 32 + 32);
preimage.extend_from_slice(&[0x19, 0x01]);
preimage.extend_from_slice(ds.as_slice());
preimage.extend_from_slice(sh.as_slice());
keccak256(preimage)
}
}
impl SRC16Domain {
pub fn separator(&self) -> [u8; 32] {
let mut tokens: Vec<u8> = Vec::new();
tokens.extend_from_slice(src16_domain_type_hash(self).as_ref());
if self.name.is_some() {
tokens.extend_from_slice(keccak256(self.name.clone().unwrap()).as_slice());
}
if self.version.is_some() {
tokens.extend_from_slice(keccak256(self.version.clone().unwrap()).as_slice());
}
if self.chain_id.is_some() {
tokens.extend(
self.chain_id
.unwrap()
.0
.iter()
.flat_map(|x| x.to_be_bytes()),
);
}
if self.verifying_contract.is_some() {
tokens.extend_from_slice(self.verifying_contract.unwrap().as_slice());
}
if self.salt.is_some() {
tokens.extend_from_slice(self.salt.unwrap().0.as_slice());
}
keccak256(tokens)
}
}
fn src16_domain_type_hash(domain: &SRC16Domain) -> [u8; 32] {
let mut fields = Vec::new();
if domain.name.is_some() {
fields.push("string name");
}
if domain.version.is_some() {
fields.push("string version");
}
if domain.chain_id.is_some() {
fields.push("u256 chain_id");
}
if domain.verifying_contract.is_some() {
fields.push("contractId verifying_contract");
}
if domain.salt.is_some() {
fields.push("b256 salt");
}
let type_string = format!("SRC16Domain({})", fields.join(","));
keccak256(type_string.as_bytes())
}
impl From<EIP712Domain> for EVMDomain {
fn from(domain: EIP712Domain) -> Self {
let chain_id = domain.chain_id.map(|id| Ethers256(id.0));
let verifying_contract = domain
.verifying_contract
.map(|contract| H160(fuel_contract_id_to_evm_address(contract.0)));
let salt = domain.salt.map(|s| s.0);
EVMDomain {
name: domain.name,
version: domain.version,
chain_id,
verifying_contract,
salt,
}
}
}
pub trait SRC16Encode {
#[allow(dead_code)]
fn type_hash(encoding: Encoding) -> [u8; 32];
fn struct_hash(self, encoding: Encoding) -> [u8; 32];
}
fn from_compact_or_standard(bytes: &[u8]) -> anyhow::Result<EthSig> {
match bytes.len() {
65 => Ok(EthSig::try_from(bytes)?),
64 => {
let r = U256::from_big_endian(&bytes[..32]);
let mut s_bytes = [0u8; 32];
s_bytes.copy_from_slice(&bytes[32..64]);
let y_parity = (s_bytes[0] >> 7) & 1;
s_bytes[0] &= 0x7F;
let s = U256::from_big_endian(&s_bytes);
let v = 27 + y_parity as u64;
Ok(EthSig { r, s, v })
}
n => anyhow::bail!("invalid length {n}, expected 64 or 65"),
}
}
pub trait SignatureCurve {
type Address;
fn verify_owner<T>(
&self,
nonce: u64,
chain_id: ChainId,
f_name: String,
args: Option<T>,
address: &Self::Address,
) -> anyhow::Result<()>
where
T: Tokenizable;
fn verify_session<T>(
&self,
nonce: u64,
args: T,
address: &Self::Address,
) -> anyhow::Result<()>
where
T: Tokenizable;
fn verify_typed<T>(
&self,
args: T,
domain: &Domain,
address: &Self::Address,
) -> anyhow::Result<()>
where
T: SRC16Encode;
}
pub struct Secp256k1Address(pub fuels::types::Address);
impl SignatureCurve for Secp256k1 {
type Address = Secp256k1Address;
fn verify_owner<T>(
&self,
nonce: u64,
chain_id: ChainId,
f_name: String,
args: Option<T>,
address: &Self::Address,
) -> anyhow::Result<()>
where
T: Tokenizable,
{
let address = &address.0;
if address.starts_with([0u8; EVM_ADDRESS_PADDING_LENGTH].as_ref()) {
let evm_address = &address[EVM_ADDRESS_PADDING_LENGTH..];
let evm_message = if let Some(args_some) = args {
calldata!((nonce, *chain_id, f_name, args_some))?
} else {
calldata!((nonce, *chain_id, f_name))?
};
let evm_sig = from_compact_or_standard(&self.bits)?;
let recovered_address = evm_sig.recover(&evm_message[..])?;
if recovered_address.as_bytes() != evm_address {
anyhow::bail!("invalid evm address provided");
}
evm_sig.verify(evm_message, recovered_address)?;
} else {
let fuel_message = generate_signing_payload(nonce, *chain_id, f_name, args);
let fuels_sig = fuels::crypto::Signature::from_bytes(self.bits);
let recovered_pub_key = fuels_sig.recover(&fuel_message)?;
if *recovered_pub_key.hash() != address.as_ref() {
anyhow::bail!("invalid fuel address provided");
}
fuels_sig.verify(&recovered_pub_key, &fuel_message)?;
}
Ok(())
}
fn verify_session<T>(
&self,
nonce: u64,
args: T,
address: &Self::Address,
) -> anyhow::Result<()>
where
T: Tokenizable,
{
let address = &address.0;
let fuel_message = generate_session_signing_payload(nonce, args);
let fuels_sig = fuels::crypto::Signature::from_bytes(self.bits);
let recovered_pub_key = fuels_sig.recover(&fuel_message)?;
if *recovered_pub_key.hash() != address.as_ref() {
anyhow::bail!("invalid fuel address provided");
}
fuels_sig.verify(&recovered_pub_key, &fuel_message)?;
Ok(())
}
fn verify_typed<T>(
&self,
args: T,
domain: &Domain,
address: &Self::Address,
) -> anyhow::Result<()>
where
T: SRC16Encode,
{
let address = &address.0;
let message: Message = Message::from_bytes(domain.encode(args));
if address.starts_with([0u8; EVM_ADDRESS_PADDING_LENGTH].as_ref()) {
let evm_address = &address[EVM_ADDRESS_PADDING_LENGTH..];
let evm_sig = from_compact_or_standard(&self.bits)?;
let recovered_address = evm_sig.recover(message.as_ref())?;
if recovered_address.as_bytes() != evm_address {
anyhow::bail!("invalid evm address provided");
}
evm_sig
.verify(RecoveryMessage::Hash((*message).into()), recovered_address)?;
} else {
let fuels_sig = fuels::crypto::Signature::from_bytes(self.bits);
let recovered_pub_key = fuels_sig.recover(&message)?;
if *recovered_pub_key.hash() != address.as_ref() {
anyhow::bail!("invalid fuel address provided");
}
fuels_sig.verify(&recovered_pub_key, &message)?;
}
Ok(())
}
}
pub enum Address {
Secp256k1(Secp256k1Address),
Secp256r1,
Ed25519,
}
impl From<fuels::types::Address> for Address {
fn from(addr: fuels::types::Address) -> Self {
Address::Secp256k1(Secp256k1Address(addr))
}
}
impl Signature {
pub fn verify_owner<T>(
&self,
nonce: u64,
chain_id: ChainId,
f_name: String,
args: Option<T>,
address: &Address,
) -> anyhow::Result<()>
where
T: Tokenizable,
{
match (self, address) {
(Signature::Secp256k1(sig), Address::Secp256k1(addr)) => {
sig.verify_owner(nonce, chain_id, f_name, args, addr)
}
(Signature::Secp256r1(_), Address::Secp256r1) => {
anyhow::bail!(
"owner signature verification not supported for p256 signatures"
)
}
(Signature::Ed25519(_), Address::Ed25519) => {
anyhow::bail!(
"owner signature verification not supported for ed25519 signatures"
)
}
_ => anyhow::bail!("signature and address type mismatch"),
}
}
pub fn verify_session<T>(
&self,
nonce: u64,
args: T,
address: &Address,
) -> anyhow::Result<()>
where
T: Tokenizable,
{
match (self, address) {
(Signature::Secp256k1(sig), Address::Secp256k1(addr)) => {
sig.verify_session(nonce, args, addr)
}
(Signature::Secp256r1(_), Address::Secp256r1) => {
anyhow::bail!(
"session signature verification not supported for p256 signatures"
)
}
(Signature::Ed25519(_), Address::Ed25519) => {
anyhow::bail!(
"session signature verification not supported for ed25519 signatures"
)
}
_ => anyhow::bail!("signature and address type mismatch"),
}
}
pub fn verify_typed<T>(
&self,
args: T,
domain: &Domain,
address: &Address,
) -> anyhow::Result<()>
where
T: SRC16Encode,
{
match (self, address) {
(Signature::Secp256k1(sig), Address::Secp256k1(addr)) => {
sig.verify_typed(args, domain, addr)
}
(Signature::Secp256r1(_), Address::Secp256r1) => {
anyhow::bail!(
"typed signature verification not supported for p256 signatures"
)
}
(Signature::Ed25519(_), Address::Ed25519) => {
anyhow::bail!(
"typed signature verification not supported for ed25519 signatures"
)
}
_ => anyhow::bail!("signature and address type mismatch"),
}
}
}
pub const SRC_16_SIGNED_SESSION_TYPE_HASH: &str =
"0x2eb25d47a049c7084035785d680582656395f354f9484e7e3bbb2993368e46b7";
pub const EIP_712_SIGNED_SESSION_TYPE_HASH: &str =
"0xf91528e233badfd402ad99c4d1dd9d109ec218093c9dcf7432699f5bb94721e2";
impl SRC16Encode for SessionArgs {
fn type_hash(encoding: Encoding) -> [u8; 32] {
match encoding {
Encoding::SRC16 => {
Bits256::from_hex_str(SRC_16_SIGNED_SESSION_TYPE_HASH)
.unwrap()
.0
}
Encoding::EIP712 => {
Bits256::from_hex_str(EIP_712_SIGNED_SESSION_TYPE_HASH)
.unwrap()
.0
}
}
}
fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
let mut tokens: Vec<u8> = Vec::new();
match encoding {
Encoding::SRC16 => tokens.extend_from_slice(
Bits256::from_hex_str(SRC_16_SIGNED_SESSION_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
Encoding::EIP712 => tokens.extend_from_slice(
Bits256::from_hex_str(EIP_712_SIGNED_SESSION_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
}
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
match self.session_id {
Identity::Address(bits) => tokens.extend_from_slice(bits.as_slice()),
Identity::ContractId(bits) => tokens.extend_from_slice(bits.as_slice()),
}
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(self.expiry.unix.to_be_bytes().as_slice());
let contract_id_bytes: Vec<u8> = self
.contract_ids
.iter()
.flat_map(|id| id.as_ref())
.copied()
.collect();
tokens.extend_from_slice(keccak256(contract_id_bytes).as_slice());
keccak256(tokens)
}
}
pub const SRC_16_SIGNED_WITHDRAW_TYPE_HASH: &str =
"0x9732cd3b83bcf964465644c9c8546dff5d9f2e5c16c077dba9a2a2bc2b9f7188";
pub const EIP_712_SIGNED_WITHDRAW_TYPE_HASH: &str =
"0x138ab031e51a15ab8c1d21d9a203f6cc5c134d7dbb44a9fd3f6acc3231af1c32";
impl SRC16Encode for &WithdrawArgs {
fn type_hash(encoding: Encoding) -> [u8; 32] {
match encoding {
Encoding::SRC16 => {
Bits256::from_hex_str(SRC_16_SIGNED_WITHDRAW_TYPE_HASH)
.unwrap()
.0
}
Encoding::EIP712 => {
Bits256::from_hex_str(EIP_712_SIGNED_WITHDRAW_TYPE_HASH)
.unwrap()
.0
}
}
}
fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
let mut tokens: Vec<u8> = Vec::new();
match encoding {
Encoding::SRC16 => tokens.extend_from_slice(
Bits256::from_hex_str(SRC_16_SIGNED_WITHDRAW_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
Encoding::EIP712 => tokens.extend_from_slice(
Bits256::from_hex_str(EIP_712_SIGNED_WITHDRAW_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
}
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
match self.to {
Identity::Address(bits) => tokens.extend_from_slice(bits.as_slice()),
Identity::ContractId(bits) => tokens.extend_from_slice(bits.as_slice()),
}
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(self.amount.to_be_bytes().as_slice());
tokens.extend_from_slice(self.asset_id.as_slice());
keccak256(tokens)
}
}
pub const SRC_16_SIGNED_CALL_PARAMS_TYPE_HASH: &str =
"0x05816efb1220d5dd49f0abf9882712729285e7080da3dc2ba051a6ab701cf3b8";
pub const EIP_712_SIGNED_CALL_PARAMS_TYPE_HASH: &str =
"0x322b030cfd61eddd3d0acc5c37358539477197bfc2599dc09a9c75ad47f6e5b8";
impl SRC16Encode for CallParams {
fn type_hash(encoding: Encoding) -> [u8; 32] {
match encoding {
Encoding::SRC16 => {
Bits256::from_hex_str(SRC_16_SIGNED_CALL_PARAMS_TYPE_HASH)
.unwrap()
.0
}
Encoding::EIP712 => {
Bits256::from_hex_str(EIP_712_SIGNED_CALL_PARAMS_TYPE_HASH)
.unwrap()
.0
}
}
}
fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
let mut tokens: Vec<u8> = Vec::new();
match encoding {
Encoding::SRC16 => tokens.extend_from_slice(
Bits256::from_hex_str(SRC_16_SIGNED_CALL_PARAMS_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
Encoding::EIP712 => tokens.extend_from_slice(
Bits256::from_hex_str(EIP_712_SIGNED_CALL_PARAMS_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
}
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(self.coins.to_be_bytes().as_slice());
tokens.extend_from_slice(self.asset_id.as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(self.gas.to_be_bytes().as_slice());
keccak256(tokens)
}
}
pub const SRC_16_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH: &str =
"0xc8ac163d1f87886f48788901b8e5eb4eebb3edad4ae111859b2a051059920048";
pub const EIP_712_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH: &str =
"0x325b44fd679189ccd8f708a440a27448cbfd6f47f90205e8ace3f1efc27c92d6";
impl SRC16Encode for CallContractArg {
fn type_hash(encoding: Encoding) -> [u8; 32] {
match encoding {
Encoding::SRC16 => {
Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
.unwrap()
.0
}
Encoding::EIP712 => {
Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
.unwrap()
.0
}
}
}
fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
let mut tokens: Vec<u8> = Vec::new();
match encoding {
Encoding::SRC16 => tokens.extend_from_slice(
Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
Encoding::EIP712 => tokens.extend_from_slice(
Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
}
tokens.extend_from_slice(self.contract_id.as_slice());
tokens.extend_from_slice(keccak256(self.function_selector.0).as_slice());
tokens.extend_from_slice(self.call_params.struct_hash(encoding).as_slice());
match self.call_data {
Some(data) => tokens.extend_from_slice(keccak256(data.0).as_slice()),
None => tokens.extend_from_slice(keccak256(Vec::new()).as_slice()),
}
keccak256(tokens)
}
}
pub const SRC_16_SIGNED_CALL_CONTRACT_TYPE_HASH: &str =
"0x3f9265dacb0b84ea31e56285f5757a2200e743f27f0b27c3d58db09c9f62cb46";
pub const EIP_712_SIGNED_CALL_CONTRACT_TYPE_HASH: &str =
"0x26ade4c76b3df03eed7d7a2d1387896e8717f8a862414199904b8a4455b25699";
impl SRC16Encode for TradeAccountCallContractArgs {
fn type_hash(encoding: Encoding) -> [u8; 32] {
match encoding {
Encoding::SRC16 => {
Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_TYPE_HASH)
.unwrap()
.0
}
Encoding::EIP712 => {
Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_TYPE_HASH)
.unwrap()
.0
}
}
}
fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
let mut tokens: Vec<u8> = Vec::new();
match encoding {
Encoding::SRC16 => tokens.extend_from_slice(
Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
Encoding::EIP712 => tokens.extend_from_slice(
Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
}
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
tokens
.extend_from_slice(self.call_contract_args.struct_hash(encoding).as_slice());
keccak256(tokens)
}
}
pub const SRC_16_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH: &str =
"0x44c30cb1e12dbc44e06a72b087359f9af5caae554d43dada454d5f6619eabf5f";
pub const EIP_712_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH: &str =
"0x292b2913cef817f041ea01e3b02c4dd2b7184e6490f21a84ece8443e406640a1";
impl SRC16Encode for MultiCallContractArgs {
fn type_hash(encoding: Encoding) -> [u8; 32] {
match encoding {
Encoding::SRC16 => {
Bits256::from_hex_str(SRC_16_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
.unwrap()
.0
}
Encoding::EIP712 => {
Bits256::from_hex_str(EIP_712_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
.unwrap()
.0
}
}
}
fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
let mut tokens: Vec<u8> = Vec::new();
match encoding {
Encoding::SRC16 => tokens.extend_from_slice(
Bits256::from_hex_str(SRC_16_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
Encoding::EIP712 => tokens.extend_from_slice(
Bits256::from_hex_str(EIP_712_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
}
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
let mut call_buffer: Vec<u8> = Vec::new();
for call in self.call_contract_args {
let h = call.struct_hash(encoding.clone());
call_buffer.extend_from_slice(h.as_slice());
}
tokens.extend_from_slice(keccak256(call_buffer.as_slice()).as_slice());
keccak256(tokens)
}
}
pub const SRC_16_REVOKE_TYPE_HASH: &str =
"0x97c9c74c84314e9fcc4ba97ad28e9cde1eda9b79b0229b54219de0e79560ac86";
pub const EIP_712_REVOKE_TYPE_HASH: &str =
"0xf863f4b733d291f6bd744df3ba070a394dd83fced6f038a22195c1b34009dabb";
impl SRC16Encode for RevokeArgs {
fn type_hash(encoding: Encoding) -> [u8; 32] {
match encoding {
Encoding::SRC16 => Bits256::from_hex_str(SRC_16_REVOKE_TYPE_HASH).unwrap().0,
Encoding::EIP712 => {
Bits256::from_hex_str(EIP_712_REVOKE_TYPE_HASH).unwrap().0
}
}
}
fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
let mut tokens: Vec<u8> = Vec::new();
match encoding {
Encoding::SRC16 => tokens.extend_from_slice(
Bits256::from_hex_str(SRC_16_REVOKE_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
Encoding::EIP712 => tokens.extend_from_slice(
Bits256::from_hex_str(EIP_712_REVOKE_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
}
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
keccak256(tokens)
}
}
pub const SRC_16_PROXY_TARGET_TYPE_HASH: &str =
"0x523db1f70cbdfc0982627ed4e52dc429384c32e94e16ddc5fa5ab921035d8d6d";
pub const EIP_712_PROXY_TARGET_TYPE_HASH: &str =
"0xf12c7a18e931f36d11f09bd52f37183c4993a3a509ac0c2c6cec459cee7a004d";
impl SRC16Encode for SetProxyTargetArgs {
fn type_hash(encoding: Encoding) -> [u8; 32] {
match encoding {
Encoding::SRC16 => {
Bits256::from_hex_str(SRC_16_PROXY_TARGET_TYPE_HASH)
.unwrap()
.0
}
Encoding::EIP712 => {
Bits256::from_hex_str(EIP_712_PROXY_TARGET_TYPE_HASH)
.unwrap()
.0
}
}
}
fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
let mut tokens: Vec<u8> = Vec::new();
match encoding {
Encoding::SRC16 => tokens.extend_from_slice(
Bits256::from_hex_str(SRC_16_PROXY_TARGET_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
Encoding::EIP712 => tokens.extend_from_slice(
Bits256::from_hex_str(EIP_712_PROXY_TARGET_TYPE_HASH)
.unwrap()
.0
.as_slice(),
),
}
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
keccak256(tokens)
}
}