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 self.chain_id.is_some() {
109 tokens.extend(
110 self.chain_id
111 .unwrap()
112 .0
113 .iter()
114 .flat_map(|x| x.to_be_bytes()),
115 );
116 }
117
118 if self.verifying_contract.is_some() {
119 tokens.extend_from_slice(self.verifying_contract.unwrap().as_slice());
120 }
121
122 if self.salt.is_some() {
123 tokens.extend_from_slice(self.salt.unwrap().0.as_slice());
124 }
125
126 keccak256(tokens)
127 }
128}
129
130fn src16_domain_type_hash(domain: &SRC16Domain) -> [u8; 32] {
131 let mut fields = Vec::new();
132
133 if domain.name.is_some() {
135 fields.push("string name");
136 }
137 if domain.version.is_some() {
138 fields.push("string version");
139 }
140 if domain.chain_id.is_some() {
141 fields.push("u256 chain_id");
142 }
143 if domain.verifying_contract.is_some() {
144 fields.push("contractId verifying_contract");
145 }
146 if domain.salt.is_some() {
147 fields.push("b256 salt");
148 }
149
150 let type_string = format!("SRC16Domain({})", fields.join(","));
151
152 keccak256(type_string.as_bytes())
153}
154
155impl From<EIP712Domain> for EVMDomain {
156 fn from(domain: EIP712Domain) -> Self {
157 let chain_id = domain.chain_id.map(|id| Ethers256(id.0));
158 let verifying_contract = domain
159 .verifying_contract
160 .map(|contract| H160(fuel_contract_id_to_evm_address(contract.0)));
161 let salt = domain.salt.map(|s| s.0);
162
163 EVMDomain {
164 name: domain.name,
165 version: domain.version,
166 chain_id,
167 verifying_contract,
168 salt,
169 }
170 }
171}
172
173pub trait SRC16Encode {
174 #[allow(dead_code)]
175 fn type_hash(encoding: Encoding) -> [u8; 32];
176 fn struct_hash(self, encoding: Encoding) -> [u8; 32];
177}
178
179fn from_compact_or_standard(bytes: &[u8]) -> anyhow::Result<EthSig> {
180 match bytes.len() {
181 65 => Ok(EthSig::try_from(bytes)?),
182 64 => {
183 let r = U256::from_big_endian(&bytes[..32]);
184 let mut s_bytes = [0u8; 32];
185 s_bytes.copy_from_slice(&bytes[32..64]);
186
187 let y_parity = (s_bytes[0] >> 7) & 1;
188 s_bytes[0] &= 0x7F;
191
192 let s = U256::from_big_endian(&s_bytes);
193 let v = 27 + y_parity as u64;
195
196 Ok(EthSig { r, s, v })
197 }
198 n => anyhow::bail!("invalid length {n}, expected 64 or 65"),
199 }
200}
201
202pub trait SignatureCurve {
203 type Address;
204
205 fn verify_owner<T>(
207 &self,
208 nonce: u64,
209 chain_id: ChainId,
210 f_name: String,
211 args: Option<T>,
212 address: &Self::Address,
213 ) -> anyhow::Result<()>
214 where
215 T: Tokenizable;
216
217 fn verify_session<T>(
219 &self,
220 nonce: u64,
221 args: T,
222 address: &Self::Address,
223 ) -> anyhow::Result<()>
224 where
225 T: Tokenizable;
226
227 fn verify_typed<T>(
228 &self,
229 args: T,
230 domain: &Domain,
231 address: &Self::Address,
232 ) -> anyhow::Result<()>
233 where
234 T: SRC16Encode;
235}
236
237pub struct Secp256k1Address(pub fuels::types::Address);
238
239impl SignatureCurve for Secp256k1 {
240 type Address = Secp256k1Address;
241
242 fn verify_owner<T>(
243 &self,
244 nonce: u64,
245 chain_id: ChainId,
246 f_name: String,
247 args: Option<T>,
248 address: &Self::Address,
249 ) -> anyhow::Result<()>
250 where
251 T: Tokenizable,
252 {
253 let address = &address.0;
254
255 if address.starts_with([0u8; EVM_ADDRESS_PADDING_LENGTH].as_ref()) {
258 let evm_address = &address[EVM_ADDRESS_PADDING_LENGTH..];
259 let evm_message = if let Some(args_some) = args {
260 calldata!((nonce, *chain_id, f_name, args_some))?
261 } else {
262 calldata!((nonce, *chain_id, f_name))?
263 };
264 let evm_sig = from_compact_or_standard(&self.bits)?;
265 let recovered_address = evm_sig.recover(&evm_message[..])?;
266
267 if recovered_address.as_bytes() != evm_address {
268 anyhow::bail!("invalid evm address provided");
269 }
270
271 evm_sig.verify(evm_message, recovered_address)?;
272 } else {
273 let fuel_message = generate_signing_payload(nonce, *chain_id, f_name, args);
274 let fuels_sig = fuels::crypto::Signature::from_bytes(self.bits);
275 let recovered_pub_key = fuels_sig.recover(&fuel_message)?;
276
277 if *recovered_pub_key.hash() != address.as_ref() {
278 anyhow::bail!("invalid fuel address provided");
279 }
280
281 fuels_sig.verify(&recovered_pub_key, &fuel_message)?;
282 }
283
284 Ok(())
285 }
286
287 fn verify_session<T>(
288 &self,
289 nonce: u64,
290 args: T,
291 address: &Self::Address,
292 ) -> anyhow::Result<()>
293 where
294 T: Tokenizable,
295 {
296 let address = &address.0;
297 let fuel_message = generate_session_signing_payload(nonce, args);
298
299 let fuels_sig = fuels::crypto::Signature::from_bytes(self.bits);
300 let recovered_pub_key = fuels_sig.recover(&fuel_message)?;
301
302 if *recovered_pub_key.hash() != address.as_ref() {
303 anyhow::bail!("invalid fuel address provided");
304 }
305
306 fuels_sig.verify(&recovered_pub_key, &fuel_message)?;
307
308 Ok(())
309 }
310
311 fn verify_typed<T>(
312 &self,
313 args: T,
314 domain: &Domain,
315 address: &Self::Address,
316 ) -> anyhow::Result<()>
317 where
318 T: SRC16Encode,
319 {
320 let address = &address.0;
321
322 let message: Message = Message::from_bytes(domain.encode(args));
324
325 if address.starts_with([0u8; EVM_ADDRESS_PADDING_LENGTH].as_ref()) {
327 let evm_address = &address[EVM_ADDRESS_PADDING_LENGTH..];
329 let evm_sig = from_compact_or_standard(&self.bits)?;
330 let recovered_address = evm_sig.recover(message.as_ref())?;
331
332 if recovered_address.as_bytes() != evm_address {
333 anyhow::bail!("invalid evm address provided");
334 }
335
336 evm_sig
337 .verify(RecoveryMessage::Hash((*message).into()), recovered_address)?;
338 } else {
339 let fuels_sig = fuels::crypto::Signature::from_bytes(self.bits);
341 let recovered_pub_key = fuels_sig.recover(&message)?;
342
343 if *recovered_pub_key.hash() != address.as_ref() {
344 anyhow::bail!("invalid fuel address provided");
345 }
346
347 fuels_sig.verify(&recovered_pub_key, &message)?;
348 }
349
350 Ok(())
351 }
352}
353
354pub enum Address {
355 Secp256k1(Secp256k1Address),
356 Secp256r1,
357 Ed25519,
358}
359
360impl From<fuels::types::Address> for Address {
361 fn from(addr: fuels::types::Address) -> Self {
362 Address::Secp256k1(Secp256k1Address(addr))
363 }
364}
365
366impl Signature {
367 pub fn verify_owner<T>(
368 &self,
369 nonce: u64,
370 chain_id: ChainId,
371 f_name: String,
372 args: Option<T>,
373 address: &Address,
374 ) -> anyhow::Result<()>
375 where
376 T: Tokenizable,
377 {
378 match (self, address) {
379 (Signature::Secp256k1(sig), Address::Secp256k1(addr)) => {
380 sig.verify_owner(nonce, chain_id, f_name, args, addr)
381 }
382 (Signature::Secp256r1(_), Address::Secp256r1) => {
383 anyhow::bail!(
384 "owner signature verification not supported for p256 signatures"
385 )
386 }
387 (Signature::Ed25519(_), Address::Ed25519) => {
388 anyhow::bail!(
389 "owner signature verification not supported for ed25519 signatures"
390 )
391 }
392 _ => anyhow::bail!("signature and address type mismatch"),
393 }
394 }
395
396 pub fn verify_session<T>(
397 &self,
398 nonce: u64,
399 args: T,
400 address: &Address,
401 ) -> anyhow::Result<()>
402 where
403 T: Tokenizable,
404 {
405 match (self, address) {
406 (Signature::Secp256k1(sig), Address::Secp256k1(addr)) => {
407 sig.verify_session(nonce, args, addr)
408 }
409 (Signature::Secp256r1(_), Address::Secp256r1) => {
410 anyhow::bail!(
411 "session signature verification not supported for p256 signatures"
412 )
413 }
414 (Signature::Ed25519(_), Address::Ed25519) => {
415 anyhow::bail!(
416 "session signature verification not supported for ed25519 signatures"
417 )
418 }
419 _ => anyhow::bail!("signature and address type mismatch"),
420 }
421 }
422
423 pub fn verify_typed<T>(
424 &self,
425 args: T,
426 domain: &Domain,
427 address: &Address,
428 ) -> anyhow::Result<()>
429 where
430 T: SRC16Encode,
431 {
432 match (self, address) {
433 (Signature::Secp256k1(sig), Address::Secp256k1(addr)) => {
434 sig.verify_typed(args, domain, addr)
435 }
436 (Signature::Secp256r1(_), Address::Secp256r1) => {
437 anyhow::bail!(
438 "typed signature verification not supported for p256 signatures"
439 )
440 }
441 (Signature::Ed25519(_), Address::Ed25519) => {
442 anyhow::bail!(
443 "typed signature verification not supported for ed25519 signatures"
444 )
445 }
446 _ => anyhow::bail!("signature and address type mismatch"),
447 }
448 }
449}
450
451pub const SRC_16_SIGNED_SESSION_TYPE_HASH: &str =
455 "0x2eb25d47a049c7084035785d680582656395f354f9484e7e3bbb2993368e46b7";
456
457pub const EIP_712_SIGNED_SESSION_TYPE_HASH: &str =
461 "0xf91528e233badfd402ad99c4d1dd9d109ec218093c9dcf7432699f5bb94721e2";
462
463impl SRC16Encode for SessionArgs {
464 fn type_hash(encoding: Encoding) -> [u8; 32] {
465 match encoding {
466 Encoding::SRC16 => {
467 Bits256::from_hex_str(SRC_16_SIGNED_SESSION_TYPE_HASH)
468 .unwrap()
469 .0
470 }
471 Encoding::EIP712 => {
472 Bits256::from_hex_str(EIP_712_SIGNED_SESSION_TYPE_HASH)
473 .unwrap()
474 .0
475 }
476 }
477 }
478 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
479 let mut tokens: Vec<u8> = Vec::new();
480 match encoding {
481 Encoding::SRC16 => tokens.extend_from_slice(
482 Bits256::from_hex_str(SRC_16_SIGNED_SESSION_TYPE_HASH)
483 .unwrap()
484 .0
485 .as_slice(),
486 ),
487 Encoding::EIP712 => tokens.extend_from_slice(
488 Bits256::from_hex_str(EIP_712_SIGNED_SESSION_TYPE_HASH)
489 .unwrap()
490 .0
491 .as_slice(),
492 ),
493 }
494
495 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
497 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
498 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
499 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
500 match self.session_id {
502 Identity::Address(bits) => tokens.extend_from_slice(bits.as_slice()),
503 Identity::ContractId(bits) => tokens.extend_from_slice(bits.as_slice()),
504 }
505 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
507 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
508 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
509 tokens.extend_from_slice(self.expiry.unix.to_be_bytes().as_slice());
510
511 let contract_id_bytes: Vec<u8> = self
513 .contract_ids
514 .iter()
515 .flat_map(|id| id.as_ref())
516 .copied()
517 .collect();
518
519 tokens.extend_from_slice(keccak256(contract_id_bytes).as_slice());
520
521 keccak256(tokens)
522 }
523}
524
525pub const SRC_16_SIGNED_WITHDRAW_TYPE_HASH: &str =
529 "0x9732cd3b83bcf964465644c9c8546dff5d9f2e5c16c077dba9a2a2bc2b9f7188";
530
531pub const EIP_712_SIGNED_WITHDRAW_TYPE_HASH: &str =
535 "0x138ab031e51a15ab8c1d21d9a203f6cc5c134d7dbb44a9fd3f6acc3231af1c32";
536
537impl SRC16Encode for &WithdrawArgs {
538 fn type_hash(encoding: Encoding) -> [u8; 32] {
539 match encoding {
540 Encoding::SRC16 => {
541 Bits256::from_hex_str(SRC_16_SIGNED_WITHDRAW_TYPE_HASH)
542 .unwrap()
543 .0
544 }
545 Encoding::EIP712 => {
546 Bits256::from_hex_str(EIP_712_SIGNED_WITHDRAW_TYPE_HASH)
547 .unwrap()
548 .0
549 }
550 }
551 }
552 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
553 let mut tokens: Vec<u8> = Vec::new();
554 match encoding {
555 Encoding::SRC16 => tokens.extend_from_slice(
556 Bits256::from_hex_str(SRC_16_SIGNED_WITHDRAW_TYPE_HASH)
557 .unwrap()
558 .0
559 .as_slice(),
560 ),
561 Encoding::EIP712 => tokens.extend_from_slice(
562 Bits256::from_hex_str(EIP_712_SIGNED_WITHDRAW_TYPE_HASH)
563 .unwrap()
564 .0
565 .as_slice(),
566 ),
567 }
568
569 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
570 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
571 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
572 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
573 match self.to {
574 Identity::Address(bits) => tokens.extend_from_slice(bits.as_slice()),
575 Identity::ContractId(bits) => tokens.extend_from_slice(bits.as_slice()),
576 }
577 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
578 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
579 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
580 tokens.extend_from_slice(self.amount.to_be_bytes().as_slice());
581 tokens.extend_from_slice(self.asset_id.as_slice());
582
583 keccak256(tokens)
584 }
585}
586
587pub const SRC_16_SIGNED_CALL_PARAMS_TYPE_HASH: &str =
591 "0x05816efb1220d5dd49f0abf9882712729285e7080da3dc2ba051a6ab701cf3b8";
592
593pub const EIP_712_SIGNED_CALL_PARAMS_TYPE_HASH: &str =
597 "0x322b030cfd61eddd3d0acc5c37358539477197bfc2599dc09a9c75ad47f6e5b8";
598
599impl SRC16Encode for CallParams {
600 fn type_hash(encoding: Encoding) -> [u8; 32] {
601 match encoding {
602 Encoding::SRC16 => {
603 Bits256::from_hex_str(SRC_16_SIGNED_CALL_PARAMS_TYPE_HASH)
604 .unwrap()
605 .0
606 }
607 Encoding::EIP712 => {
608 Bits256::from_hex_str(EIP_712_SIGNED_CALL_PARAMS_TYPE_HASH)
609 .unwrap()
610 .0
611 }
612 }
613 }
614 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
615 let mut tokens: Vec<u8> = Vec::new();
616 match encoding {
617 Encoding::SRC16 => tokens.extend_from_slice(
618 Bits256::from_hex_str(SRC_16_SIGNED_CALL_PARAMS_TYPE_HASH)
619 .unwrap()
620 .0
621 .as_slice(),
622 ),
623 Encoding::EIP712 => tokens.extend_from_slice(
624 Bits256::from_hex_str(EIP_712_SIGNED_CALL_PARAMS_TYPE_HASH)
625 .unwrap()
626 .0
627 .as_slice(),
628 ),
629 }
630
631 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.coins.to_be_bytes().as_slice());
636 tokens.extend_from_slice(self.asset_id.as_slice());
637 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
638 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
639 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
640 tokens.extend_from_slice(self.gas.to_be_bytes().as_slice());
641
642 keccak256(tokens)
643 }
644}
645
646pub const SRC_16_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH: &str =
650 "0xc8ac163d1f87886f48788901b8e5eb4eebb3edad4ae111859b2a051059920048";
651
652pub const EIP_712_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH: &str =
656 "0x325b44fd679189ccd8f708a440a27448cbfd6f47f90205e8ace3f1efc27c92d6";
657
658impl SRC16Encode for CallContractArg {
659 fn type_hash(encoding: Encoding) -> [u8; 32] {
660 match encoding {
661 Encoding::SRC16 => {
662 Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
663 .unwrap()
664 .0
665 }
666 Encoding::EIP712 => {
667 Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
668 .unwrap()
669 .0
670 }
671 }
672 }
673 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
674 let mut tokens: Vec<u8> = Vec::new();
675 match encoding {
676 Encoding::SRC16 => tokens.extend_from_slice(
677 Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
678 .unwrap()
679 .0
680 .as_slice(),
681 ),
682 Encoding::EIP712 => tokens.extend_from_slice(
683 Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
684 .unwrap()
685 .0
686 .as_slice(),
687 ),
688 }
689
690 tokens.extend_from_slice(self.contract_id.as_slice());
692
693 tokens.extend_from_slice(keccak256(self.function_selector.0).as_slice());
695
696 tokens.extend_from_slice(self.call_params.struct_hash(encoding).as_slice());
698
699 match self.call_data {
701 Some(data) => tokens.extend_from_slice(keccak256(data.0).as_slice()),
702 None => tokens.extend_from_slice(keccak256(Vec::new()).as_slice()),
703 }
704
705 keccak256(tokens)
706 }
707}
708
709pub const SRC_16_SIGNED_CALL_CONTRACT_TYPE_HASH: &str =
713 "0x3f9265dacb0b84ea31e56285f5757a2200e743f27f0b27c3d58db09c9f62cb46";
714
715pub const EIP_712_SIGNED_CALL_CONTRACT_TYPE_HASH: &str =
719 "0x26ade4c76b3df03eed7d7a2d1387896e8717f8a862414199904b8a4455b25699";
720
721impl SRC16Encode for TradeAccountCallContractArgs {
722 fn type_hash(encoding: Encoding) -> [u8; 32] {
723 match encoding {
724 Encoding::SRC16 => {
725 Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_TYPE_HASH)
726 .unwrap()
727 .0
728 }
729 Encoding::EIP712 => {
730 Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_TYPE_HASH)
731 .unwrap()
732 .0
733 }
734 }
735 }
736 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
737 let mut tokens: Vec<u8> = Vec::new();
738 match encoding {
739 Encoding::SRC16 => tokens.extend_from_slice(
740 Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_TYPE_HASH)
741 .unwrap()
742 .0
743 .as_slice(),
744 ),
745 Encoding::EIP712 => tokens.extend_from_slice(
746 Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_TYPE_HASH)
747 .unwrap()
748 .0
749 .as_slice(),
750 ),
751 }
752
753 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
755 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
756 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
757 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
758
759 tokens
761 .extend_from_slice(self.call_contract_args.struct_hash(encoding).as_slice());
762
763 keccak256(tokens)
764 }
765}
766
767pub const SRC_16_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH: &str =
771 "0x44c30cb1e12dbc44e06a72b087359f9af5caae554d43dada454d5f6619eabf5f";
772
773pub const EIP_712_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH: &str =
777 "0x292b2913cef817f041ea01e3b02c4dd2b7184e6490f21a84ece8443e406640a1";
778
779impl SRC16Encode for MultiCallContractArgs {
780 fn type_hash(encoding: Encoding) -> [u8; 32] {
781 match encoding {
782 Encoding::SRC16 => {
783 Bits256::from_hex_str(SRC_16_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
784 .unwrap()
785 .0
786 }
787 Encoding::EIP712 => {
788 Bits256::from_hex_str(EIP_712_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
789 .unwrap()
790 .0
791 }
792 }
793 }
794 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
795 let mut tokens: Vec<u8> = Vec::new();
796 match encoding {
797 Encoding::SRC16 => tokens.extend_from_slice(
798 Bits256::from_hex_str(SRC_16_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
799 .unwrap()
800 .0
801 .as_slice(),
802 ),
803 Encoding::EIP712 => tokens.extend_from_slice(
804 Bits256::from_hex_str(EIP_712_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
805 .unwrap()
806 .0
807 .as_slice(),
808 ),
809 }
810
811 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
813 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
814 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
815 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
816
817 let mut call_buffer: Vec<u8> = Vec::new();
819 for call in self.call_contract_args {
820 let h = call.struct_hash(encoding.clone());
821 call_buffer.extend_from_slice(h.as_slice());
822 }
823 tokens.extend_from_slice(keccak256(call_buffer.as_slice()).as_slice());
824
825 keccak256(tokens)
826 }
827}
828
829pub const SRC_16_REVOKE_TYPE_HASH: &str =
833 "0x97c9c74c84314e9fcc4ba97ad28e9cde1eda9b79b0229b54219de0e79560ac86";
834
835pub const EIP_712_REVOKE_TYPE_HASH: &str =
839 "0xf863f4b733d291f6bd744df3ba070a394dd83fced6f038a22195c1b34009dabb";
840
841impl SRC16Encode for RevokeArgs {
842 fn type_hash(encoding: Encoding) -> [u8; 32] {
843 match encoding {
844 Encoding::SRC16 => Bits256::from_hex_str(SRC_16_REVOKE_TYPE_HASH).unwrap().0,
845 Encoding::EIP712 => {
846 Bits256::from_hex_str(EIP_712_REVOKE_TYPE_HASH).unwrap().0
847 }
848 }
849 }
850 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
851 let mut tokens: Vec<u8> = Vec::new();
852 match encoding {
853 Encoding::SRC16 => tokens.extend_from_slice(
854 Bits256::from_hex_str(SRC_16_REVOKE_TYPE_HASH)
855 .unwrap()
856 .0
857 .as_slice(),
858 ),
859 Encoding::EIP712 => tokens.extend_from_slice(
860 Bits256::from_hex_str(EIP_712_REVOKE_TYPE_HASH)
861 .unwrap()
862 .0
863 .as_slice(),
864 ),
865 }
866
867 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
868 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
869 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
870 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
871
872 keccak256(tokens)
873 }
874}
875
876pub const SRC_16_PROXY_TARGET_TYPE_HASH: &str =
880 "0x523db1f70cbdfc0982627ed4e52dc429384c32e94e16ddc5fa5ab921035d8d6d";
881
882pub const EIP_712_PROXY_TARGET_TYPE_HASH: &str =
886 "0xf12c7a18e931f36d11f09bd52f37183c4993a3a509ac0c2c6cec459cee7a004d";
887
888impl SRC16Encode for SetProxyTargetArgs {
889 fn type_hash(encoding: Encoding) -> [u8; 32] {
890 match encoding {
891 Encoding::SRC16 => {
892 Bits256::from_hex_str(SRC_16_PROXY_TARGET_TYPE_HASH)
893 .unwrap()
894 .0
895 }
896 Encoding::EIP712 => {
897 Bits256::from_hex_str(EIP_712_PROXY_TARGET_TYPE_HASH)
898 .unwrap()
899 .0
900 }
901 }
902 }
903 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
904 let mut tokens: Vec<u8> = Vec::new();
905 match encoding {
906 Encoding::SRC16 => tokens.extend_from_slice(
907 Bits256::from_hex_str(SRC_16_PROXY_TARGET_TYPE_HASH)
908 .unwrap()
909 .0
910 .as_slice(),
911 ),
912 Encoding::EIP712 => tokens.extend_from_slice(
913 Bits256::from_hex_str(EIP_712_PROXY_TARGET_TYPE_HASH)
914 .unwrap()
915 .0
916 .as_slice(),
917 ),
918 }
919
920 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
921 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
922 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
923 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
924
925 keccak256(tokens)
926 }
927}