1use fuels::{
2 core::{
3 codec::calldata,
4 traits::Tokenizable,
5 },
6 crypto::Message,
7 types::{
8 Bits256,
9 ChainId,
10 Identity,
11 },
12};
13
14use crate::{
15 trade_account::{
16 generate_session_signing_payload,
17 generate_signing_payload,
18 },
19 trade_account_deploy::{
20 CallContractArg,
21 CallContractArgs as TradeAccountCallContractArgs,
22 CallParams,
23 Domain,
24 EIP712Domain,
25 Encoding,
26 MultiCallContractArgs,
27 RevokeArgs,
28 SRC16Domain,
29 Secp256k1,
30 SessionArgs,
31 SetProxyTargetArgs,
32 Signature,
33 WithdrawArgs,
34 },
35};
36use ethers_core::{
37 types::{
38 H160,
39 RecoveryMessage,
40 Signature as EthSig,
41 U256,
42 U256 as Ethers256,
43 transaction::eip712::EIP712Domain as EVMDomain,
44 },
45 utils::keccak256,
46};
47
48const EVM_ADDRESS_PADDING_LENGTH: usize = 12;
49
50fn fuel_contract_id_to_evm_address(id: [u8; 32]) -> [u8; 20] {
53 let mut addr = [0u8; 20];
54 addr.copy_from_slice(&id[12..32]);
56 addr
57}
58
59pub trait DomainExt {
60 fn separator(&self) -> [u8; 32];
61 fn encode<T>(&self, struct_type: T) -> [u8; 32]
62 where
63 T: SRC16Encode;
64}
65
66impl DomainExt for Domain {
67 fn separator(&self) -> [u8; 32] {
68 match self {
69 Domain::EIP712Domain(d) => EVMDomain::from(d.clone()).separator(),
70 Domain::SRC16Domain(d) => d.separator(),
71 }
72 }
73
74 fn encode<T>(&self, struct_type: T) -> [u8; 32]
75 where
76 T: SRC16Encode,
77 {
78 let ds = self.separator();
79 let encoding = match self {
80 Domain::SRC16Domain(_) => Encoding::SRC16,
81 Domain::EIP712Domain(_) => Encoding::EIP712,
82 };
83 let sh = struct_type.struct_hash(encoding);
84
85 let mut preimage = Vec::with_capacity(2 + 32 + 32);
86 preimage.extend_from_slice(&[0x19, 0x01]);
87 preimage.extend_from_slice(ds.as_slice());
88 preimage.extend_from_slice(sh.as_slice());
89
90 keccak256(preimage)
91 }
92}
93
94impl SRC16Domain {
95 pub fn separator(&self) -> [u8; 32] {
97 let mut tokens: Vec<u8> = Vec::new();
98
99 tokens.extend_from_slice(src16_domain_type_hash(self).as_ref());
100
101 if self.name.is_some() {
102 tokens.extend_from_slice(keccak256(self.name.clone().unwrap()).as_slice());
103 }
104 if self.version.is_some() {
105 tokens.extend_from_slice(keccak256(self.version.clone().unwrap()).as_slice());
106 }
107
108 if let Some(chain_id) = self.chain_id {
109 tokens.extend(chain_id.0.iter().flat_map(|x| x.to_be_bytes()));
110 }
111
112 if let Some(verifying_contract) = self.verifying_contract {
113 tokens.extend_from_slice(verifying_contract.as_slice());
114 }
115
116 if let Some(salt) = self.salt {
117 tokens.extend_from_slice(salt.0.as_slice());
118 }
119
120 keccak256(tokens)
121 }
122}
123
124fn src16_domain_type_hash(domain: &SRC16Domain) -> [u8; 32] {
125 let mut fields = Vec::new();
126
127 if domain.name.is_some() {
129 fields.push("string name");
130 }
131 if domain.version.is_some() {
132 fields.push("string version");
133 }
134 if domain.chain_id.is_some() {
135 fields.push("u256 chain_id");
136 }
137 if domain.verifying_contract.is_some() {
138 fields.push("contractId verifying_contract");
139 }
140 if domain.salt.is_some() {
141 fields.push("b256 salt");
142 }
143
144 let type_string = format!("SRC16Domain({})", fields.join(","));
145
146 keccak256(type_string.as_bytes())
147}
148
149impl From<EIP712Domain> for EVMDomain {
150 fn from(domain: EIP712Domain) -> Self {
151 let chain_id = domain.chain_id.map(|id| Ethers256(id.0));
152 let verifying_contract = domain
153 .verifying_contract
154 .map(|contract| H160(fuel_contract_id_to_evm_address(contract.0)));
155 let salt = domain.salt.map(|s| s.0);
156
157 EVMDomain {
158 name: domain.name,
159 version: domain.version,
160 chain_id,
161 verifying_contract,
162 salt,
163 }
164 }
165}
166
167pub trait SRC16Encode {
168 #[allow(dead_code)]
169 fn type_hash(encoding: Encoding) -> [u8; 32];
170 fn struct_hash(self, encoding: Encoding) -> [u8; 32];
171}
172
173fn from_compact_or_standard(bytes: &[u8]) -> anyhow::Result<EthSig> {
174 match bytes.len() {
175 65 => Ok(EthSig::try_from(bytes)?),
176 64 => {
177 let r = U256::from_big_endian(&bytes[..32]);
178 let mut s_bytes = [0u8; 32];
179 s_bytes.copy_from_slice(&bytes[32..64]);
180
181 let y_parity = (s_bytes[0] >> 7) & 1;
182 s_bytes[0] &= 0x7F;
185
186 let s = U256::from_big_endian(&s_bytes);
187 let v = 27 + y_parity as u64;
189
190 Ok(EthSig { r, s, v })
191 }
192 n => anyhow::bail!("invalid length {n}, expected 64 or 65"),
193 }
194}
195
196pub trait SignatureCurve {
197 type Address;
198
199 fn verify_owner<T>(
201 &self,
202 nonce: u64,
203 chain_id: ChainId,
204 f_name: String,
205 args: Option<T>,
206 address: &Self::Address,
207 ) -> anyhow::Result<()>
208 where
209 T: Tokenizable;
210
211 fn verify_session<T>(
213 &self,
214 nonce: u64,
215 args: T,
216 address: &Self::Address,
217 ) -> anyhow::Result<()>
218 where
219 T: Tokenizable;
220
221 fn verify_typed<T>(
222 &self,
223 args: T,
224 domain: &Domain,
225 address: &Self::Address,
226 ) -> anyhow::Result<()>
227 where
228 T: SRC16Encode;
229}
230
231pub struct Secp256k1Address(pub fuels::types::Address);
232
233impl SignatureCurve for Secp256k1 {
234 type Address = Secp256k1Address;
235
236 fn verify_owner<T>(
237 &self,
238 nonce: u64,
239 chain_id: ChainId,
240 f_name: String,
241 args: Option<T>,
242 address: &Self::Address,
243 ) -> anyhow::Result<()>
244 where
245 T: Tokenizable,
246 {
247 let address = &address.0;
248
249 if address.starts_with([0u8; EVM_ADDRESS_PADDING_LENGTH].as_ref()) {
252 let evm_address = &address[EVM_ADDRESS_PADDING_LENGTH..];
253 let evm_message = if let Some(args_some) = args {
254 calldata!((nonce, *chain_id, f_name, args_some))?
255 } else {
256 calldata!((nonce, *chain_id, f_name))?
257 };
258 let evm_sig = from_compact_or_standard(&self.bits)?;
259 let recovered_address = evm_sig.recover(&evm_message[..])?;
260
261 if recovered_address.as_bytes() != evm_address {
262 anyhow::bail!("invalid evm address provided");
263 }
264
265 evm_sig.verify(evm_message, recovered_address)?;
266 } else {
267 let fuel_message = generate_signing_payload(nonce, *chain_id, f_name, args);
268 let fuels_sig = fuels::crypto::Signature::from_bytes(self.bits);
269 let recovered_pub_key = fuels_sig.recover(&fuel_message)?;
270
271 if *recovered_pub_key.hash() != address.as_ref() {
272 anyhow::bail!("invalid fuel address provided");
273 }
274
275 fuels_sig.verify(&recovered_pub_key, &fuel_message)?;
276 }
277
278 Ok(())
279 }
280
281 fn verify_session<T>(
282 &self,
283 nonce: u64,
284 args: T,
285 address: &Self::Address,
286 ) -> anyhow::Result<()>
287 where
288 T: Tokenizable,
289 {
290 let address = &address.0;
291 let fuel_message = generate_session_signing_payload(nonce, args);
292
293 let fuels_sig = fuels::crypto::Signature::from_bytes(self.bits);
294 let recovered_pub_key = fuels_sig.recover(&fuel_message)?;
295
296 if *recovered_pub_key.hash() != address.as_ref() {
297 anyhow::bail!("invalid fuel address provided");
298 }
299
300 fuels_sig.verify(&recovered_pub_key, &fuel_message)?;
301
302 Ok(())
303 }
304
305 fn verify_typed<T>(
306 &self,
307 args: T,
308 domain: &Domain,
309 address: &Self::Address,
310 ) -> anyhow::Result<()>
311 where
312 T: SRC16Encode,
313 {
314 let address = &address.0;
315
316 let message: Message = Message::from_bytes(domain.encode(args));
318
319 if address.starts_with([0u8; EVM_ADDRESS_PADDING_LENGTH].as_ref()) {
321 let evm_address = &address[EVM_ADDRESS_PADDING_LENGTH..];
323 let evm_sig = from_compact_or_standard(&self.bits)?;
324 let recovered_address =
325 evm_sig.recover(RecoveryMessage::Hash((*message).into()))?;
326
327 if recovered_address.as_bytes() != evm_address {
328 anyhow::bail!("invalid evm address provided");
329 }
330
331 evm_sig
332 .verify(RecoveryMessage::Hash((*message).into()), recovered_address)?;
333 } else {
334 let fuels_sig = fuels::crypto::Signature::from_bytes(self.bits);
336 let recovered_pub_key = fuels_sig.recover(&message)?;
337
338 if *recovered_pub_key.hash() != address.as_ref() {
339 anyhow::bail!("invalid fuel address provided");
340 }
341
342 fuels_sig.verify(&recovered_pub_key, &message)?;
343 }
344
345 Ok(())
346 }
347}
348
349pub enum Address {
350 Secp256k1(Secp256k1Address),
351 Secp256r1,
352 Ed25519,
353}
354
355impl From<fuels::types::Address> for Address {
356 fn from(addr: fuels::types::Address) -> Self {
357 Address::Secp256k1(Secp256k1Address(addr))
358 }
359}
360
361impl Signature {
362 pub fn verify_owner<T>(
363 &self,
364 nonce: u64,
365 chain_id: ChainId,
366 f_name: String,
367 args: Option<T>,
368 address: &Address,
369 ) -> anyhow::Result<()>
370 where
371 T: Tokenizable,
372 {
373 match (self, address) {
374 (Signature::Secp256k1(sig), Address::Secp256k1(addr)) => {
375 sig.verify_owner(nonce, chain_id, f_name, args, addr)
376 }
377 (Signature::Secp256r1(_), Address::Secp256r1) => {
378 anyhow::bail!(
379 "owner signature verification not supported for p256 signatures"
380 )
381 }
382 (Signature::Ed25519(_), Address::Ed25519) => {
383 anyhow::bail!(
384 "owner signature verification not supported for ed25519 signatures"
385 )
386 }
387 _ => anyhow::bail!("signature and address type mismatch"),
388 }
389 }
390
391 pub fn verify_session<T>(
392 &self,
393 nonce: u64,
394 args: T,
395 address: &Address,
396 ) -> anyhow::Result<()>
397 where
398 T: Tokenizable,
399 {
400 match (self, address) {
401 (Signature::Secp256k1(sig), Address::Secp256k1(addr)) => {
402 sig.verify_session(nonce, args, addr)
403 }
404 (Signature::Secp256r1(_), Address::Secp256r1) => {
405 anyhow::bail!(
406 "session signature verification not supported for p256 signatures"
407 )
408 }
409 (Signature::Ed25519(_), Address::Ed25519) => {
410 anyhow::bail!(
411 "session signature verification not supported for ed25519 signatures"
412 )
413 }
414 _ => anyhow::bail!("signature and address type mismatch"),
415 }
416 }
417
418 pub fn verify_typed<T>(
419 &self,
420 args: T,
421 domain: &Domain,
422 address: &Address,
423 ) -> anyhow::Result<()>
424 where
425 T: SRC16Encode,
426 {
427 match (self, address) {
428 (Signature::Secp256k1(sig), Address::Secp256k1(addr)) => {
429 sig.verify_typed(args, domain, addr)
430 }
431 (Signature::Secp256r1(_), Address::Secp256r1) => {
432 anyhow::bail!(
433 "typed signature verification not supported for p256 signatures"
434 )
435 }
436 (Signature::Ed25519(_), Address::Ed25519) => {
437 anyhow::bail!(
438 "typed signature verification not supported for ed25519 signatures"
439 )
440 }
441 _ => anyhow::bail!("signature and address type mismatch"),
442 }
443 }
444}
445
446pub const SRC_16_SIGNED_SESSION_TYPE_HASH: &str =
450 "0x2eb25d47a049c7084035785d680582656395f354f9484e7e3bbb2993368e46b7";
451
452pub const EIP_712_SIGNED_SESSION_TYPE_HASH: &str =
456 "0xf91528e233badfd402ad99c4d1dd9d109ec218093c9dcf7432699f5bb94721e2";
457
458impl SRC16Encode for SessionArgs {
459 fn type_hash(encoding: Encoding) -> [u8; 32] {
460 match encoding {
461 Encoding::SRC16 => {
462 Bits256::from_hex_str(SRC_16_SIGNED_SESSION_TYPE_HASH)
463 .unwrap()
464 .0
465 }
466 Encoding::EIP712 => {
467 Bits256::from_hex_str(EIP_712_SIGNED_SESSION_TYPE_HASH)
468 .unwrap()
469 .0
470 }
471 }
472 }
473 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
474 let mut tokens: Vec<u8> = Vec::new();
475 match encoding {
476 Encoding::SRC16 => tokens.extend_from_slice(
477 Bits256::from_hex_str(SRC_16_SIGNED_SESSION_TYPE_HASH)
478 .unwrap()
479 .0
480 .as_slice(),
481 ),
482 Encoding::EIP712 => tokens.extend_from_slice(
483 Bits256::from_hex_str(EIP_712_SIGNED_SESSION_TYPE_HASH)
484 .unwrap()
485 .0
486 .as_slice(),
487 ),
488 }
489
490 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
492 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
493 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
494 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
495 match self.session_id {
497 Identity::Address(bits) => tokens.extend_from_slice(bits.as_slice()),
498 Identity::ContractId(bits) => tokens.extend_from_slice(bits.as_slice()),
499 }
500 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
502 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
503 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
504 tokens.extend_from_slice(self.expiry.unix.to_be_bytes().as_slice());
505
506 let contract_id_bytes: Vec<u8> = self
508 .contract_ids
509 .iter()
510 .flat_map(|id| id.as_ref())
511 .copied()
512 .collect();
513
514 tokens.extend_from_slice(keccak256(contract_id_bytes).as_slice());
515
516 keccak256(tokens)
517 }
518}
519
520pub const SRC_16_SIGNED_WITHDRAW_TYPE_HASH: &str =
524 "0x9732cd3b83bcf964465644c9c8546dff5d9f2e5c16c077dba9a2a2bc2b9f7188";
525
526pub const EIP_712_SIGNED_WITHDRAW_TYPE_HASH: &str =
530 "0x138ab031e51a15ab8c1d21d9a203f6cc5c134d7dbb44a9fd3f6acc3231af1c32";
531
532impl SRC16Encode for &WithdrawArgs {
533 fn type_hash(encoding: Encoding) -> [u8; 32] {
534 match encoding {
535 Encoding::SRC16 => {
536 Bits256::from_hex_str(SRC_16_SIGNED_WITHDRAW_TYPE_HASH)
537 .unwrap()
538 .0
539 }
540 Encoding::EIP712 => {
541 Bits256::from_hex_str(EIP_712_SIGNED_WITHDRAW_TYPE_HASH)
542 .unwrap()
543 .0
544 }
545 }
546 }
547 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
548 let mut tokens: Vec<u8> = Vec::new();
549 match encoding {
550 Encoding::SRC16 => tokens.extend_from_slice(
551 Bits256::from_hex_str(SRC_16_SIGNED_WITHDRAW_TYPE_HASH)
552 .unwrap()
553 .0
554 .as_slice(),
555 ),
556 Encoding::EIP712 => tokens.extend_from_slice(
557 Bits256::from_hex_str(EIP_712_SIGNED_WITHDRAW_TYPE_HASH)
558 .unwrap()
559 .0
560 .as_slice(),
561 ),
562 }
563
564 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
565 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
566 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
567 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
568 match self.to {
569 Identity::Address(bits) => tokens.extend_from_slice(bits.as_slice()),
570 Identity::ContractId(bits) => tokens.extend_from_slice(bits.as_slice()),
571 }
572 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
573 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
574 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
575 tokens.extend_from_slice(self.amount.to_be_bytes().as_slice());
576 tokens.extend_from_slice(self.asset_id.as_slice());
577
578 keccak256(tokens)
579 }
580}
581
582pub const SRC_16_SIGNED_CALL_PARAMS_TYPE_HASH: &str =
586 "0x05816efb1220d5dd49f0abf9882712729285e7080da3dc2ba051a6ab701cf3b8";
587
588pub const EIP_712_SIGNED_CALL_PARAMS_TYPE_HASH: &str =
592 "0x322b030cfd61eddd3d0acc5c37358539477197bfc2599dc09a9c75ad47f6e5b8";
593
594impl SRC16Encode for CallParams {
595 fn type_hash(encoding: Encoding) -> [u8; 32] {
596 match encoding {
597 Encoding::SRC16 => {
598 Bits256::from_hex_str(SRC_16_SIGNED_CALL_PARAMS_TYPE_HASH)
599 .unwrap()
600 .0
601 }
602 Encoding::EIP712 => {
603 Bits256::from_hex_str(EIP_712_SIGNED_CALL_PARAMS_TYPE_HASH)
604 .unwrap()
605 .0
606 }
607 }
608 }
609 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
610 let mut tokens: Vec<u8> = Vec::new();
611 match encoding {
612 Encoding::SRC16 => tokens.extend_from_slice(
613 Bits256::from_hex_str(SRC_16_SIGNED_CALL_PARAMS_TYPE_HASH)
614 .unwrap()
615 .0
616 .as_slice(),
617 ),
618 Encoding::EIP712 => tokens.extend_from_slice(
619 Bits256::from_hex_str(EIP_712_SIGNED_CALL_PARAMS_TYPE_HASH)
620 .unwrap()
621 .0
622 .as_slice(),
623 ),
624 }
625
626 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
628 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
629 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
630 tokens.extend_from_slice(self.coins.to_be_bytes().as_slice());
631 tokens.extend_from_slice(self.asset_id.as_slice());
632 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
633 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
634 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
635 tokens.extend_from_slice(self.gas.to_be_bytes().as_slice());
636
637 keccak256(tokens)
638 }
639}
640
641pub const SRC_16_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH: &str =
645 "0xc8ac163d1f87886f48788901b8e5eb4eebb3edad4ae111859b2a051059920048";
646
647pub const EIP_712_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH: &str =
651 "0x325b44fd679189ccd8f708a440a27448cbfd6f47f90205e8ace3f1efc27c92d6";
652
653impl SRC16Encode for CallContractArg {
654 fn type_hash(encoding: Encoding) -> [u8; 32] {
655 match encoding {
656 Encoding::SRC16 => {
657 Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
658 .unwrap()
659 .0
660 }
661 Encoding::EIP712 => {
662 Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
663 .unwrap()
664 .0
665 }
666 }
667 }
668 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
669 let mut tokens: Vec<u8> = Vec::new();
670 match encoding {
671 Encoding::SRC16 => tokens.extend_from_slice(
672 Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
673 .unwrap()
674 .0
675 .as_slice(),
676 ),
677 Encoding::EIP712 => tokens.extend_from_slice(
678 Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
679 .unwrap()
680 .0
681 .as_slice(),
682 ),
683 }
684
685 tokens.extend_from_slice(self.contract_id.as_slice());
687
688 tokens.extend_from_slice(keccak256(self.function_selector.0).as_slice());
690
691 tokens.extend_from_slice(self.call_params.struct_hash(encoding).as_slice());
693
694 match self.call_data {
696 Some(data) => tokens.extend_from_slice(keccak256(data.0).as_slice()),
697 None => tokens.extend_from_slice(keccak256(Vec::new()).as_slice()),
698 }
699
700 keccak256(tokens)
701 }
702}
703
704pub const SRC_16_SIGNED_CALL_CONTRACT_TYPE_HASH: &str =
708 "0x3f9265dacb0b84ea31e56285f5757a2200e743f27f0b27c3d58db09c9f62cb46";
709
710pub const EIP_712_SIGNED_CALL_CONTRACT_TYPE_HASH: &str =
714 "0x26ade4c76b3df03eed7d7a2d1387896e8717f8a862414199904b8a4455b25699";
715
716impl SRC16Encode for TradeAccountCallContractArgs {
717 fn type_hash(encoding: Encoding) -> [u8; 32] {
718 match encoding {
719 Encoding::SRC16 => {
720 Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_TYPE_HASH)
721 .unwrap()
722 .0
723 }
724 Encoding::EIP712 => {
725 Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_TYPE_HASH)
726 .unwrap()
727 .0
728 }
729 }
730 }
731 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
732 let mut tokens: Vec<u8> = Vec::new();
733 match encoding {
734 Encoding::SRC16 => tokens.extend_from_slice(
735 Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_TYPE_HASH)
736 .unwrap()
737 .0
738 .as_slice(),
739 ),
740 Encoding::EIP712 => tokens.extend_from_slice(
741 Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_TYPE_HASH)
742 .unwrap()
743 .0
744 .as_slice(),
745 ),
746 }
747
748 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
750 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
751 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
752 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
753
754 tokens
756 .extend_from_slice(self.call_contract_args.struct_hash(encoding).as_slice());
757
758 keccak256(tokens)
759 }
760}
761
762pub const SRC_16_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH: &str =
766 "0x44c30cb1e12dbc44e06a72b087359f9af5caae554d43dada454d5f6619eabf5f";
767
768pub const EIP_712_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH: &str =
772 "0x292b2913cef817f041ea01e3b02c4dd2b7184e6490f21a84ece8443e406640a1";
773
774impl SRC16Encode for MultiCallContractArgs {
775 fn type_hash(encoding: Encoding) -> [u8; 32] {
776 match encoding {
777 Encoding::SRC16 => {
778 Bits256::from_hex_str(SRC_16_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
779 .unwrap()
780 .0
781 }
782 Encoding::EIP712 => {
783 Bits256::from_hex_str(EIP_712_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
784 .unwrap()
785 .0
786 }
787 }
788 }
789 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
790 let mut tokens: Vec<u8> = Vec::new();
791 match encoding {
792 Encoding::SRC16 => tokens.extend_from_slice(
793 Bits256::from_hex_str(SRC_16_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
794 .unwrap()
795 .0
796 .as_slice(),
797 ),
798 Encoding::EIP712 => tokens.extend_from_slice(
799 Bits256::from_hex_str(EIP_712_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
800 .unwrap()
801 .0
802 .as_slice(),
803 ),
804 }
805
806 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
808 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
809 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
810 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
811
812 let mut call_buffer: Vec<u8> = Vec::new();
814 for call in self.call_contract_args {
815 let h = call.struct_hash(encoding.clone());
816 call_buffer.extend_from_slice(h.as_slice());
817 }
818 tokens.extend_from_slice(keccak256(call_buffer.as_slice()).as_slice());
819
820 keccak256(tokens)
821 }
822}
823
824pub const SRC_16_REVOKE_TYPE_HASH: &str =
828 "0x97c9c74c84314e9fcc4ba97ad28e9cde1eda9b79b0229b54219de0e79560ac86";
829
830pub const EIP_712_REVOKE_TYPE_HASH: &str =
834 "0xf863f4b733d291f6bd744df3ba070a394dd83fced6f038a22195c1b34009dabb";
835
836impl SRC16Encode for RevokeArgs {
837 fn type_hash(encoding: Encoding) -> [u8; 32] {
838 match encoding {
839 Encoding::SRC16 => Bits256::from_hex_str(SRC_16_REVOKE_TYPE_HASH).unwrap().0,
840 Encoding::EIP712 => {
841 Bits256::from_hex_str(EIP_712_REVOKE_TYPE_HASH).unwrap().0
842 }
843 }
844 }
845 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
846 let mut tokens: Vec<u8> = Vec::new();
847 match encoding {
848 Encoding::SRC16 => tokens.extend_from_slice(
849 Bits256::from_hex_str(SRC_16_REVOKE_TYPE_HASH)
850 .unwrap()
851 .0
852 .as_slice(),
853 ),
854 Encoding::EIP712 => tokens.extend_from_slice(
855 Bits256::from_hex_str(EIP_712_REVOKE_TYPE_HASH)
856 .unwrap()
857 .0
858 .as_slice(),
859 ),
860 }
861
862 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
863 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
864 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
865 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
866
867 keccak256(tokens)
868 }
869}
870
871pub const SRC_16_PROXY_TARGET_TYPE_HASH: &str =
875 "0x523db1f70cbdfc0982627ed4e52dc429384c32e94e16ddc5fa5ab921035d8d6d";
876
877pub const EIP_712_PROXY_TARGET_TYPE_HASH: &str =
881 "0xf12c7a18e931f36d11f09bd52f37183c4993a3a509ac0c2c6cec459cee7a004d";
882
883impl SRC16Encode for SetProxyTargetArgs {
884 fn type_hash(encoding: Encoding) -> [u8; 32] {
885 match encoding {
886 Encoding::SRC16 => {
887 Bits256::from_hex_str(SRC_16_PROXY_TARGET_TYPE_HASH)
888 .unwrap()
889 .0
890 }
891 Encoding::EIP712 => {
892 Bits256::from_hex_str(EIP_712_PROXY_TARGET_TYPE_HASH)
893 .unwrap()
894 .0
895 }
896 }
897 }
898 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
899 let mut tokens: Vec<u8> = Vec::new();
900 match encoding {
901 Encoding::SRC16 => tokens.extend_from_slice(
902 Bits256::from_hex_str(SRC_16_PROXY_TARGET_TYPE_HASH)
903 .unwrap()
904 .0
905 .as_slice(),
906 ),
907 Encoding::EIP712 => tokens.extend_from_slice(
908 Bits256::from_hex_str(EIP_712_PROXY_TARGET_TYPE_HASH)
909 .unwrap()
910 .0
911 .as_slice(),
912 ),
913 }
914
915 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
916 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
917 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
918 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
919
920 keccak256(tokens)
921 }
922}