1use fuels::{
2 core::{
3 codec::calldata,
4 traits::Tokenizable,
5 },
6 crypto::Message,
7 types::{
8 Bits256,
9 ChainId,
10 Identity,
11 U256 as FuelU256,
12 },
13};
14
15use crate::{
16 trade_account::{
17 generate_session_signing_payload,
18 generate_signing_payload,
19 },
20 trade_account_deploy::{
21 CallContractArg,
22 CallContractArgs as TradeAccountCallContractArgs,
23 CallParams,
24 Domain,
25 EIP712Domain,
26 Encoding,
27 MultiCallContractArgs,
28 ParallelCallContractArg,
29 ParallelCallContractArgs,
30 ParallelMultiCallContractArgs,
31 ParallelRevokeArgs,
32 ParallelSessionArgs,
33 ParallelWithdrawArgs,
34 RevokeArgs,
35 SRC16Domain,
36 Secp256k1,
37 SessionArgs,
38 SetProxyTargetArgs,
39 Signature,
40 WithdrawArgs,
41 },
42};
43use ethers_core::{
44 types::{
45 H160,
46 RecoveryMessage,
47 Signature as EthSig,
48 U256,
49 U256 as Ethers256,
50 transaction::eip712::EIP712Domain as EVMDomain,
51 },
52 utils::keccak256,
53};
54
55const EVM_ADDRESS_PADDING_LENGTH: usize = 12;
56
57fn fuel_contract_id_to_evm_address(id: [u8; 32]) -> [u8; 20] {
60 let mut addr = [0u8; 20];
61 addr.copy_from_slice(&id[12..32]);
63 addr
64}
65
66pub trait DomainExt {
67 fn separator(&self) -> [u8; 32];
68 fn encode<T>(&self, struct_type: T) -> [u8; 32]
69 where
70 T: SRC16Encode;
71}
72
73impl DomainExt for Domain {
74 fn separator(&self) -> [u8; 32] {
75 match self {
76 Domain::EIP712Domain(d) => EVMDomain::from(d.clone()).separator(),
77 Domain::SRC16Domain(d) => d.separator(),
78 }
79 }
80
81 fn encode<T>(&self, struct_type: T) -> [u8; 32]
82 where
83 T: SRC16Encode,
84 {
85 let ds = self.separator();
86 let encoding = match self {
87 Domain::SRC16Domain(_) => Encoding::SRC16,
88 Domain::EIP712Domain(_) => Encoding::EIP712,
89 };
90 let sh = struct_type.struct_hash(encoding);
91
92 let mut preimage = Vec::with_capacity(2 + 32 + 32);
93 preimage.extend_from_slice(&[0x19, 0x01]);
94 preimage.extend_from_slice(ds.as_slice());
95 preimage.extend_from_slice(sh.as_slice());
96
97 keccak256(preimage)
98 }
99}
100
101impl SRC16Domain {
102 pub fn separator(&self) -> [u8; 32] {
104 let mut tokens: Vec<u8> = Vec::new();
105
106 tokens.extend_from_slice(src16_domain_type_hash(self).as_ref());
107
108 if self.name.is_some() {
109 tokens.extend_from_slice(keccak256(self.name.clone().unwrap()).as_slice());
110 }
111 if self.version.is_some() {
112 tokens.extend_from_slice(keccak256(self.version.clone().unwrap()).as_slice());
113 }
114
115 if let Some(chain_id) = self.chain_id {
116 tokens.extend(chain_id.0.iter().flat_map(|x| x.to_be_bytes()));
117 }
118
119 if let Some(verifying_contract) = self.verifying_contract {
120 tokens.extend_from_slice(verifying_contract.as_slice());
121 }
122
123 if let Some(salt) = self.salt {
124 tokens.extend_from_slice(salt.0.as_slice());
125 }
126
127 keccak256(tokens)
128 }
129}
130
131fn src16_domain_type_hash(domain: &SRC16Domain) -> [u8; 32] {
132 let mut fields = Vec::new();
133
134 if domain.name.is_some() {
136 fields.push("string name");
137 }
138 if domain.version.is_some() {
139 fields.push("string version");
140 }
141 if domain.chain_id.is_some() {
142 fields.push("u256 chain_id");
143 }
144 if domain.verifying_contract.is_some() {
145 fields.push("contractId verifying_contract");
146 }
147 if domain.salt.is_some() {
148 fields.push("b256 salt");
149 }
150
151 let type_string = format!("SRC16Domain({})", fields.join(","));
152
153 keccak256(type_string.as_bytes())
154}
155
156fn fuel_u256_to_bytes(value: &FuelU256) -> [u8; 32] {
157 let mut bytes = [0u8; 32];
158 value.to_big_endian(&mut bytes);
159 bytes
160}
161
162impl From<EIP712Domain> for EVMDomain {
163 fn from(domain: EIP712Domain) -> Self {
164 let chain_id = domain.chain_id.map(|id| Ethers256(id.0));
165 let verifying_contract = domain
166 .verifying_contract
167 .map(|contract| H160(fuel_contract_id_to_evm_address(contract.0)));
168 let salt = domain.salt.map(|s| s.0);
169
170 EVMDomain {
171 name: domain.name,
172 version: domain.version,
173 chain_id,
174 verifying_contract,
175 salt,
176 }
177 }
178}
179
180pub trait SRC16Encode {
181 #[allow(dead_code)]
182 fn type_hash(encoding: Encoding) -> [u8; 32];
183 fn struct_hash(self, encoding: Encoding) -> [u8; 32];
184}
185
186fn from_compact_or_standard(bytes: &[u8]) -> anyhow::Result<EthSig> {
187 match bytes.len() {
188 65 => Ok(EthSig::try_from(bytes)?),
189 64 => {
190 let r = U256::from_big_endian(&bytes[..32]);
191 let mut s_bytes = [0u8; 32];
192 s_bytes.copy_from_slice(&bytes[32..64]);
193
194 let y_parity = (s_bytes[0] >> 7) & 1;
195 s_bytes[0] &= 0x7F;
198
199 let s = U256::from_big_endian(&s_bytes);
200 let v = 27 + y_parity as u64;
202
203 Ok(EthSig { r, s, v })
204 }
205 n => anyhow::bail!("invalid length {n}, expected 64 or 65"),
206 }
207}
208
209pub trait SignatureCurve {
210 type Address;
211
212 fn verify_owner<T>(
214 &self,
215 nonce: u64,
216 chain_id: ChainId,
217 f_name: String,
218 args: Option<T>,
219 address: &Self::Address,
220 ) -> anyhow::Result<()>
221 where
222 T: Tokenizable;
223
224 fn verify_session<T>(
226 &self,
227 nonce: u64,
228 args: T,
229 address: &Self::Address,
230 ) -> anyhow::Result<()>
231 where
232 T: Tokenizable;
233
234 fn verify_typed<T>(
235 &self,
236 args: T,
237 domain: &Domain,
238 address: &Self::Address,
239 ) -> anyhow::Result<()>
240 where
241 T: SRC16Encode;
242}
243
244pub struct Secp256k1Address(pub fuels::types::Address);
245
246impl SignatureCurve for Secp256k1 {
247 type Address = Secp256k1Address;
248
249 fn verify_owner<T>(
250 &self,
251 nonce: u64,
252 chain_id: ChainId,
253 f_name: String,
254 args: Option<T>,
255 address: &Self::Address,
256 ) -> anyhow::Result<()>
257 where
258 T: Tokenizable,
259 {
260 let address = &address.0;
261
262 if address.starts_with([0u8; EVM_ADDRESS_PADDING_LENGTH].as_ref()) {
265 let evm_address = &address[EVM_ADDRESS_PADDING_LENGTH..];
266 let evm_message = if let Some(args_some) = args {
267 calldata!((nonce, *chain_id, f_name, args_some))?
268 } else {
269 calldata!((nonce, *chain_id, f_name))?
270 };
271 let evm_sig = from_compact_or_standard(&self.bits)?;
272 let recovered_address = evm_sig.recover(&evm_message[..])?;
273
274 if recovered_address.as_bytes() != evm_address {
275 anyhow::bail!("invalid evm address provided");
276 }
277
278 evm_sig.verify(evm_message, recovered_address)?;
279 } else {
280 let fuel_message = generate_signing_payload(nonce, *chain_id, f_name, args);
281 let fuels_sig = fuels::crypto::Signature::from_bytes(self.bits);
282 let recovered_pub_key = fuels_sig.recover(&fuel_message)?;
283
284 if *recovered_pub_key.hash() != address.as_ref() {
285 anyhow::bail!("invalid fuel address provided");
286 }
287
288 fuels_sig.verify(&recovered_pub_key, &fuel_message)?;
289 }
290
291 Ok(())
292 }
293
294 fn verify_session<T>(
295 &self,
296 nonce: u64,
297 args: T,
298 address: &Self::Address,
299 ) -> anyhow::Result<()>
300 where
301 T: Tokenizable,
302 {
303 let address = &address.0;
304 let fuel_message = generate_session_signing_payload(nonce, args);
305
306 let fuels_sig = fuels::crypto::Signature::from_bytes(self.bits);
307 let recovered_pub_key = fuels_sig.recover(&fuel_message)?;
308
309 if *recovered_pub_key.hash() != address.as_ref() {
310 anyhow::bail!("invalid fuel address provided");
311 }
312
313 fuels_sig.verify(&recovered_pub_key, &fuel_message)?;
314
315 Ok(())
316 }
317
318 fn verify_typed<T>(
319 &self,
320 args: T,
321 domain: &Domain,
322 address: &Self::Address,
323 ) -> anyhow::Result<()>
324 where
325 T: SRC16Encode,
326 {
327 let address = &address.0;
328
329 let message: Message = Message::from_bytes(domain.encode(args));
331
332 if address.starts_with([0u8; EVM_ADDRESS_PADDING_LENGTH].as_ref()) {
334 let evm_address = &address[EVM_ADDRESS_PADDING_LENGTH..];
336 let evm_sig = from_compact_or_standard(&self.bits)?;
337 let recovered_address =
338 evm_sig.recover(RecoveryMessage::Hash((*message).into()))?;
339
340 if recovered_address.as_bytes() != evm_address {
341 anyhow::bail!("invalid evm address provided");
342 }
343
344 evm_sig
345 .verify(RecoveryMessage::Hash((*message).into()), recovered_address)?;
346 } else {
347 let fuels_sig = fuels::crypto::Signature::from_bytes(self.bits);
349 let recovered_pub_key = fuels_sig.recover(&message)?;
350
351 if *recovered_pub_key.hash() != address.as_ref() {
352 anyhow::bail!("invalid fuel address provided");
353 }
354
355 fuels_sig.verify(&recovered_pub_key, &message)?;
356 }
357
358 Ok(())
359 }
360}
361
362pub enum Address {
363 Secp256k1(Secp256k1Address),
364 Secp256r1,
365 Ed25519,
366}
367
368impl From<fuels::types::Address> for Address {
369 fn from(addr: fuels::types::Address) -> Self {
370 Address::Secp256k1(Secp256k1Address(addr))
371 }
372}
373
374impl Signature {
375 pub fn verify_owner<T>(
376 &self,
377 nonce: u64,
378 chain_id: ChainId,
379 f_name: String,
380 args: Option<T>,
381 address: &Address,
382 ) -> anyhow::Result<()>
383 where
384 T: Tokenizable,
385 {
386 match (self, address) {
387 (Signature::Secp256k1(sig), Address::Secp256k1(addr)) => {
388 sig.verify_owner(nonce, chain_id, f_name, args, addr)
389 }
390 (Signature::Secp256r1(_), Address::Secp256r1) => {
391 anyhow::bail!(
392 "owner signature verification not supported for p256 signatures"
393 )
394 }
395 (Signature::Ed25519(_), Address::Ed25519) => {
396 anyhow::bail!(
397 "owner signature verification not supported for ed25519 signatures"
398 )
399 }
400 _ => anyhow::bail!("signature and address type mismatch"),
401 }
402 }
403
404 pub fn verify_session<T>(
405 &self,
406 nonce: u64,
407 args: T,
408 address: &Address,
409 ) -> anyhow::Result<()>
410 where
411 T: Tokenizable,
412 {
413 match (self, address) {
414 (Signature::Secp256k1(sig), Address::Secp256k1(addr)) => {
415 sig.verify_session(nonce, args, addr)
416 }
417 (Signature::Secp256r1(_), Address::Secp256r1) => {
418 anyhow::bail!(
419 "session signature verification not supported for p256 signatures"
420 )
421 }
422 (Signature::Ed25519(_), Address::Ed25519) => {
423 anyhow::bail!(
424 "session signature verification not supported for ed25519 signatures"
425 )
426 }
427 _ => anyhow::bail!("signature and address type mismatch"),
428 }
429 }
430
431 pub fn verify_typed<T>(
432 &self,
433 args: T,
434 domain: &Domain,
435 address: &Address,
436 ) -> anyhow::Result<()>
437 where
438 T: SRC16Encode,
439 {
440 match (self, address) {
441 (Signature::Secp256k1(sig), Address::Secp256k1(addr)) => {
442 sig.verify_typed(args, domain, addr)
443 }
444 (Signature::Secp256r1(_), Address::Secp256r1) => {
445 anyhow::bail!(
446 "typed signature verification not supported for p256 signatures"
447 )
448 }
449 (Signature::Ed25519(_), Address::Ed25519) => {
450 anyhow::bail!(
451 "typed signature verification not supported for ed25519 signatures"
452 )
453 }
454 _ => anyhow::bail!("signature and address type mismatch"),
455 }
456 }
457}
458
459pub const SRC_16_SIGNED_SESSION_TYPE_HASH: &str =
463 "0x2eb25d47a049c7084035785d680582656395f354f9484e7e3bbb2993368e46b7";
464
465pub const EIP_712_SIGNED_SESSION_TYPE_HASH: &str =
469 "0xf91528e233badfd402ad99c4d1dd9d109ec218093c9dcf7432699f5bb94721e2";
470
471impl SRC16Encode for SessionArgs {
472 fn type_hash(encoding: Encoding) -> [u8; 32] {
473 match encoding {
474 Encoding::SRC16 => {
475 Bits256::from_hex_str(SRC_16_SIGNED_SESSION_TYPE_HASH)
476 .unwrap()
477 .0
478 }
479 Encoding::EIP712 => {
480 Bits256::from_hex_str(EIP_712_SIGNED_SESSION_TYPE_HASH)
481 .unwrap()
482 .0
483 }
484 }
485 }
486 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
487 let mut tokens: Vec<u8> = Vec::new();
488 match encoding {
489 Encoding::SRC16 => tokens.extend_from_slice(
490 Bits256::from_hex_str(SRC_16_SIGNED_SESSION_TYPE_HASH)
491 .unwrap()
492 .0
493 .as_slice(),
494 ),
495 Encoding::EIP712 => tokens.extend_from_slice(
496 Bits256::from_hex_str(EIP_712_SIGNED_SESSION_TYPE_HASH)
497 .unwrap()
498 .0
499 .as_slice(),
500 ),
501 }
502
503 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
505 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
506 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
507 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
508 match self.session_id {
510 Identity::Address(bits) => tokens.extend_from_slice(bits.as_slice()),
511 Identity::ContractId(bits) => tokens.extend_from_slice(bits.as_slice()),
512 }
513 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
515 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
516 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
517 tokens.extend_from_slice(self.expiry.unix.to_be_bytes().as_slice());
518
519 let contract_id_bytes: Vec<u8> = self
521 .contract_ids
522 .iter()
523 .flat_map(|id| id.as_ref())
524 .copied()
525 .collect();
526
527 tokens.extend_from_slice(keccak256(contract_id_bytes).as_slice());
528
529 keccak256(tokens)
530 }
531}
532
533pub const SRC_16_SIGNED_WITHDRAW_TYPE_HASH: &str =
537 "0x9732cd3b83bcf964465644c9c8546dff5d9f2e5c16c077dba9a2a2bc2b9f7188";
538
539pub const EIP_712_SIGNED_WITHDRAW_TYPE_HASH: &str =
543 "0x138ab031e51a15ab8c1d21d9a203f6cc5c134d7dbb44a9fd3f6acc3231af1c32";
544
545impl SRC16Encode for &WithdrawArgs {
546 fn type_hash(encoding: Encoding) -> [u8; 32] {
547 match encoding {
548 Encoding::SRC16 => {
549 Bits256::from_hex_str(SRC_16_SIGNED_WITHDRAW_TYPE_HASH)
550 .unwrap()
551 .0
552 }
553 Encoding::EIP712 => {
554 Bits256::from_hex_str(EIP_712_SIGNED_WITHDRAW_TYPE_HASH)
555 .unwrap()
556 .0
557 }
558 }
559 }
560 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
561 let mut tokens: Vec<u8> = Vec::new();
562 match encoding {
563 Encoding::SRC16 => tokens.extend_from_slice(
564 Bits256::from_hex_str(SRC_16_SIGNED_WITHDRAW_TYPE_HASH)
565 .unwrap()
566 .0
567 .as_slice(),
568 ),
569 Encoding::EIP712 => tokens.extend_from_slice(
570 Bits256::from_hex_str(EIP_712_SIGNED_WITHDRAW_TYPE_HASH)
571 .unwrap()
572 .0
573 .as_slice(),
574 ),
575 }
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.nonce.to_be_bytes().as_slice());
581 match self.to {
582 Identity::Address(bits) => tokens.extend_from_slice(bits.as_slice()),
583 Identity::ContractId(bits) => tokens.extend_from_slice(bits.as_slice()),
584 }
585 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
586 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
587 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
588 tokens.extend_from_slice(self.amount.to_be_bytes().as_slice());
589 tokens.extend_from_slice(self.asset_id.as_slice());
590
591 keccak256(tokens)
592 }
593}
594
595pub const SRC_16_SIGNED_CALL_PARAMS_TYPE_HASH: &str =
599 "0x05816efb1220d5dd49f0abf9882712729285e7080da3dc2ba051a6ab701cf3b8";
600
601pub const EIP_712_SIGNED_CALL_PARAMS_TYPE_HASH: &str =
605 "0x322b030cfd61eddd3d0acc5c37358539477197bfc2599dc09a9c75ad47f6e5b8";
606
607impl SRC16Encode for CallParams {
608 fn type_hash(encoding: Encoding) -> [u8; 32] {
609 match encoding {
610 Encoding::SRC16 => {
611 Bits256::from_hex_str(SRC_16_SIGNED_CALL_PARAMS_TYPE_HASH)
612 .unwrap()
613 .0
614 }
615 Encoding::EIP712 => {
616 Bits256::from_hex_str(EIP_712_SIGNED_CALL_PARAMS_TYPE_HASH)
617 .unwrap()
618 .0
619 }
620 }
621 }
622 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
623 let mut tokens: Vec<u8> = Vec::new();
624 match encoding {
625 Encoding::SRC16 => tokens.extend_from_slice(
626 Bits256::from_hex_str(SRC_16_SIGNED_CALL_PARAMS_TYPE_HASH)
627 .unwrap()
628 .0
629 .as_slice(),
630 ),
631 Encoding::EIP712 => tokens.extend_from_slice(
632 Bits256::from_hex_str(EIP_712_SIGNED_CALL_PARAMS_TYPE_HASH)
633 .unwrap()
634 .0
635 .as_slice(),
636 ),
637 }
638
639 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
641 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
642 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
643 tokens.extend_from_slice(self.coins.to_be_bytes().as_slice());
644 tokens.extend_from_slice(self.asset_id.as_slice());
645 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
646 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
647 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
648 tokens.extend_from_slice(self.gas.to_be_bytes().as_slice());
649
650 keccak256(tokens)
651 }
652}
653
654pub const SRC_16_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH: &str =
658 "0xc8ac163d1f87886f48788901b8e5eb4eebb3edad4ae111859b2a051059920048";
659
660pub const EIP_712_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH: &str =
664 "0x325b44fd679189ccd8f708a440a27448cbfd6f47f90205e8ace3f1efc27c92d6";
665
666impl SRC16Encode for CallContractArg {
667 fn type_hash(encoding: Encoding) -> [u8; 32] {
668 match encoding {
669 Encoding::SRC16 => {
670 Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
671 .unwrap()
672 .0
673 }
674 Encoding::EIP712 => {
675 Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
676 .unwrap()
677 .0
678 }
679 }
680 }
681 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
682 let mut tokens: Vec<u8> = Vec::new();
683 match encoding {
684 Encoding::SRC16 => tokens.extend_from_slice(
685 Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
686 .unwrap()
687 .0
688 .as_slice(),
689 ),
690 Encoding::EIP712 => tokens.extend_from_slice(
691 Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
692 .unwrap()
693 .0
694 .as_slice(),
695 ),
696 }
697
698 tokens.extend_from_slice(self.contract_id.as_slice());
700
701 tokens.extend_from_slice(keccak256(self.function_selector.0).as_slice());
703
704 tokens.extend_from_slice(self.call_params.struct_hash(encoding).as_slice());
706
707 match self.call_data {
709 Some(data) => tokens.extend_from_slice(keccak256(data.0).as_slice()),
710 None => tokens.extend_from_slice(keccak256(Vec::new()).as_slice()),
711 }
712
713 keccak256(tokens)
714 }
715}
716
717pub const SRC_16_SIGNED_CALL_CONTRACT_TYPE_HASH: &str =
721 "0x3f9265dacb0b84ea31e56285f5757a2200e743f27f0b27c3d58db09c9f62cb46";
722
723pub const EIP_712_SIGNED_CALL_CONTRACT_TYPE_HASH: &str =
727 "0x26ade4c76b3df03eed7d7a2d1387896e8717f8a862414199904b8a4455b25699";
728
729impl SRC16Encode for TradeAccountCallContractArgs {
730 fn type_hash(encoding: Encoding) -> [u8; 32] {
731 match encoding {
732 Encoding::SRC16 => {
733 Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_TYPE_HASH)
734 .unwrap()
735 .0
736 }
737 Encoding::EIP712 => {
738 Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_TYPE_HASH)
739 .unwrap()
740 .0
741 }
742 }
743 }
744 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
745 let mut tokens: Vec<u8> = Vec::new();
746 match encoding {
747 Encoding::SRC16 => tokens.extend_from_slice(
748 Bits256::from_hex_str(SRC_16_SIGNED_CALL_CONTRACT_TYPE_HASH)
749 .unwrap()
750 .0
751 .as_slice(),
752 ),
753 Encoding::EIP712 => tokens.extend_from_slice(
754 Bits256::from_hex_str(EIP_712_SIGNED_CALL_CONTRACT_TYPE_HASH)
755 .unwrap()
756 .0
757 .as_slice(),
758 ),
759 }
760
761 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
763 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
764 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
765 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
766
767 tokens
769 .extend_from_slice(self.call_contract_args.struct_hash(encoding).as_slice());
770
771 keccak256(tokens)
772 }
773}
774
775pub const SRC_16_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH: &str =
779 "0x44c30cb1e12dbc44e06a72b087359f9af5caae554d43dada454d5f6619eabf5f";
780
781pub const EIP_712_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH: &str =
785 "0x292b2913cef817f041ea01e3b02c4dd2b7184e6490f21a84ece8443e406640a1";
786
787impl SRC16Encode for MultiCallContractArgs {
788 fn type_hash(encoding: Encoding) -> [u8; 32] {
789 match encoding {
790 Encoding::SRC16 => {
791 Bits256::from_hex_str(SRC_16_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
792 .unwrap()
793 .0
794 }
795 Encoding::EIP712 => {
796 Bits256::from_hex_str(EIP_712_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
797 .unwrap()
798 .0
799 }
800 }
801 }
802 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
803 let mut tokens: Vec<u8> = Vec::new();
804 match encoding {
805 Encoding::SRC16 => tokens.extend_from_slice(
806 Bits256::from_hex_str(SRC_16_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
807 .unwrap()
808 .0
809 .as_slice(),
810 ),
811 Encoding::EIP712 => tokens.extend_from_slice(
812 Bits256::from_hex_str(EIP_712_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH)
813 .unwrap()
814 .0
815 .as_slice(),
816 ),
817 }
818
819 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
821 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
822 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
823 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
824
825 let mut call_buffer: Vec<u8> = Vec::new();
827 for call in self.call_contract_args {
828 let h = call.struct_hash(encoding.clone());
829 call_buffer.extend_from_slice(h.as_slice());
830 }
831 tokens.extend_from_slice(keccak256(call_buffer.as_slice()).as_slice());
832
833 keccak256(tokens)
834 }
835}
836
837pub const SRC_16_REVOKE_TYPE_HASH: &str =
841 "0x97c9c74c84314e9fcc4ba97ad28e9cde1eda9b79b0229b54219de0e79560ac86";
842
843pub const EIP_712_REVOKE_TYPE_HASH: &str =
847 "0xf863f4b733d291f6bd744df3ba070a394dd83fced6f038a22195c1b34009dabb";
848
849impl SRC16Encode for RevokeArgs {
850 fn type_hash(encoding: Encoding) -> [u8; 32] {
851 match encoding {
852 Encoding::SRC16 => Bits256::from_hex_str(SRC_16_REVOKE_TYPE_HASH).unwrap().0,
853 Encoding::EIP712 => {
854 Bits256::from_hex_str(EIP_712_REVOKE_TYPE_HASH).unwrap().0
855 }
856 }
857 }
858 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
859 let mut tokens: Vec<u8> = Vec::new();
860 match encoding {
861 Encoding::SRC16 => tokens.extend_from_slice(
862 Bits256::from_hex_str(SRC_16_REVOKE_TYPE_HASH)
863 .unwrap()
864 .0
865 .as_slice(),
866 ),
867 Encoding::EIP712 => tokens.extend_from_slice(
868 Bits256::from_hex_str(EIP_712_REVOKE_TYPE_HASH)
869 .unwrap()
870 .0
871 .as_slice(),
872 ),
873 }
874
875 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
876 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
877 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
878 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
879
880 keccak256(tokens)
881 }
882}
883
884pub const SRC_16_PROXY_TARGET_TYPE_HASH: &str =
888 "0x523db1f70cbdfc0982627ed4e52dc429384c32e94e16ddc5fa5ab921035d8d6d";
889
890pub const EIP_712_PROXY_TARGET_TYPE_HASH: &str =
894 "0xf12c7a18e931f36d11f09bd52f37183c4993a3a509ac0c2c6cec459cee7a004d";
895
896impl SRC16Encode for SetProxyTargetArgs {
897 fn type_hash(encoding: Encoding) -> [u8; 32] {
898 match encoding {
899 Encoding::SRC16 => {
900 Bits256::from_hex_str(SRC_16_PROXY_TARGET_TYPE_HASH)
901 .unwrap()
902 .0
903 }
904 Encoding::EIP712 => {
905 Bits256::from_hex_str(EIP_712_PROXY_TARGET_TYPE_HASH)
906 .unwrap()
907 .0
908 }
909 }
910 }
911 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
912 let mut tokens: Vec<u8> = Vec::new();
913 match encoding {
914 Encoding::SRC16 => tokens.extend_from_slice(
915 Bits256::from_hex_str(SRC_16_PROXY_TARGET_TYPE_HASH)
916 .unwrap()
917 .0
918 .as_slice(),
919 ),
920 Encoding::EIP712 => tokens.extend_from_slice(
921 Bits256::from_hex_str(EIP_712_PROXY_TARGET_TYPE_HASH)
922 .unwrap()
923 .0
924 .as_slice(),
925 ),
926 }
927
928 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
929 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
930 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
931 tokens.extend_from_slice(self.nonce.to_be_bytes().as_slice());
932
933 keccak256(tokens)
934 }
935}
936
937pub const SRC_16_PARALLEL_SIGNED_SESSION_TYPE_HASH: &str =
938 "0x7bcb65ebf5b9c6a7eb6a5d92462eeb2b3eba824e9c8f22c2b01533c2e3364019";
939
940pub const EIP_712_PARALLEL_SIGNED_SESSION_TYPE_HASH: &str =
941 "0x67a8adc215ea9fc6e3a50e038c7c123758629a96e6f33c3a5b6bd8534842d9a7";
942
943impl SRC16Encode for &ParallelSessionArgs {
944 fn type_hash(encoding: Encoding) -> [u8; 32] {
945 match encoding {
946 Encoding::SRC16 => {
947 Bits256::from_hex_str(SRC_16_PARALLEL_SIGNED_SESSION_TYPE_HASH)
948 .unwrap()
949 .0
950 }
951 Encoding::EIP712 => {
952 Bits256::from_hex_str(EIP_712_PARALLEL_SIGNED_SESSION_TYPE_HASH)
953 .unwrap()
954 .0
955 }
956 }
957 }
958
959 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
960 let mut tokens: Vec<u8> = Vec::new();
961 match encoding {
962 Encoding::SRC16 => tokens.extend_from_slice(
963 Bits256::from_hex_str(SRC_16_PARALLEL_SIGNED_SESSION_TYPE_HASH)
964 .unwrap()
965 .0
966 .as_slice(),
967 ),
968 Encoding::EIP712 => tokens.extend_from_slice(
969 Bits256::from_hex_str(EIP_712_PARALLEL_SIGNED_SESSION_TYPE_HASH)
970 .unwrap()
971 .0
972 .as_slice(),
973 ),
974 }
975
976 tokens.extend_from_slice(fuel_u256_to_bytes(&self.nonce).as_slice());
977 match self.session_id {
978 Identity::Address(bits) => tokens.extend_from_slice(bits.as_slice()),
979 Identity::ContractId(bits) => tokens.extend_from_slice(bits.as_slice()),
980 }
981 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
982 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
983 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
984 tokens.extend_from_slice(self.expiry.unix.to_be_bytes().as_slice());
985
986 let contract_id_bytes: Vec<u8> = self
987 .contract_ids
988 .iter()
989 .flat_map(|id| id.as_ref())
990 .copied()
991 .collect();
992 tokens.extend_from_slice(keccak256(contract_id_bytes).as_slice());
993
994 keccak256(tokens)
995 }
996}
997
998pub const SRC_16_PARALLEL_SIGNED_WITHDRAW_TYPE_HASH: &str =
999 "0x95a9c4c23dd3607b14ecdc67fcc42946f61a4f1d153dc7dfbd77ca6c2af1c6f6";
1000
1001pub const EIP_712_PARALLEL_SIGNED_WITHDRAW_TYPE_HASH: &str =
1002 "0x7d2e70c357f073fd00c187b1871bf74c440ec8303b435f001d884d6ffd77ca1c";
1003
1004impl SRC16Encode for &ParallelWithdrawArgs {
1005 fn type_hash(encoding: Encoding) -> [u8; 32] {
1006 match encoding {
1007 Encoding::SRC16 => {
1008 Bits256::from_hex_str(SRC_16_PARALLEL_SIGNED_WITHDRAW_TYPE_HASH)
1009 .unwrap()
1010 .0
1011 }
1012 Encoding::EIP712 => {
1013 Bits256::from_hex_str(EIP_712_PARALLEL_SIGNED_WITHDRAW_TYPE_HASH)
1014 .unwrap()
1015 .0
1016 }
1017 }
1018 }
1019
1020 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
1021 let mut tokens: Vec<u8> = Vec::new();
1022 match encoding {
1023 Encoding::SRC16 => tokens.extend_from_slice(
1024 Bits256::from_hex_str(SRC_16_PARALLEL_SIGNED_WITHDRAW_TYPE_HASH)
1025 .unwrap()
1026 .0
1027 .as_slice(),
1028 ),
1029 Encoding::EIP712 => tokens.extend_from_slice(
1030 Bits256::from_hex_str(EIP_712_PARALLEL_SIGNED_WITHDRAW_TYPE_HASH)
1031 .unwrap()
1032 .0
1033 .as_slice(),
1034 ),
1035 }
1036
1037 tokens.extend_from_slice(fuel_u256_to_bytes(&self.nonce).as_slice());
1038 match self.to {
1039 Identity::Address(bits) => tokens.extend_from_slice(bits.as_slice()),
1040 Identity::ContractId(bits) => tokens.extend_from_slice(bits.as_slice()),
1041 }
1042 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
1043 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
1044 tokens.extend_from_slice(0u64.to_be_bytes().as_slice());
1045 tokens.extend_from_slice(self.amount.to_be_bytes().as_slice());
1046 tokens.extend_from_slice(self.asset_id.as_slice());
1047
1048 keccak256(tokens)
1049 }
1050}
1051
1052pub const SRC_16_PARALLEL_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH: &str =
1053 "0x4b0849aa7446711dce1e67cef7c4fb412bf532bcef8e55645b311d5fe670e430";
1054
1055pub const EIP_712_PARALLEL_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH: &str =
1056 "0x06588b3fa3b32122be787ca84fefaf67ae00491f90a3333b0f1a6bf23991d21b";
1057
1058impl SRC16Encode for ParallelCallContractArg {
1059 fn type_hash(encoding: Encoding) -> [u8; 32] {
1060 match encoding {
1061 Encoding::SRC16 => {
1062 Bits256::from_hex_str(SRC_16_PARALLEL_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
1063 .unwrap()
1064 .0
1065 }
1066 Encoding::EIP712 => {
1067 Bits256::from_hex_str(EIP_712_PARALLEL_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
1068 .unwrap()
1069 .0
1070 }
1071 }
1072 }
1073
1074 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
1075 let mut tokens: Vec<u8> = Vec::new();
1076 match encoding {
1077 Encoding::SRC16 => tokens.extend_from_slice(
1078 Bits256::from_hex_str(SRC_16_PARALLEL_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH)
1079 .unwrap()
1080 .0
1081 .as_slice(),
1082 ),
1083 Encoding::EIP712 => tokens.extend_from_slice(
1084 Bits256::from_hex_str(
1085 EIP_712_PARALLEL_SIGNED_CALL_CONTRACT_ARG_TYPE_HASH,
1086 )
1087 .unwrap()
1088 .0
1089 .as_slice(),
1090 ),
1091 }
1092
1093 tokens.extend_from_slice(self.contract_id.as_slice());
1094 tokens.extend_from_slice(keccak256(self.function_selector.0).as_slice());
1095 tokens.extend_from_slice(self.call_params.struct_hash(encoding).as_slice());
1096 match self.call_data {
1097 Some(data) => tokens.extend_from_slice(keccak256(data.0).as_slice()),
1098 None => tokens.extend_from_slice(keccak256(Vec::new()).as_slice()),
1099 }
1100
1101 keccak256(tokens)
1102 }
1103}
1104
1105pub const SRC_16_PARALLEL_SIGNED_CALL_CONTRACT_TYPE_HASH: &str =
1106 "0x0715266d50809ef56e0c9daa18526acc618a197db7485b2f4291450bfce0c343";
1107
1108pub const EIP_712_PARALLEL_SIGNED_CALL_CONTRACT_TYPE_HASH: &str =
1109 "0xba28dc067be2d8fec20d75fc6de7c3e3187ac4af33d8f8bf39992ac745808544";
1110
1111impl SRC16Encode for ParallelCallContractArgs {
1112 fn type_hash(encoding: Encoding) -> [u8; 32] {
1113 match encoding {
1114 Encoding::SRC16 => {
1115 Bits256::from_hex_str(SRC_16_PARALLEL_SIGNED_CALL_CONTRACT_TYPE_HASH)
1116 .unwrap()
1117 .0
1118 }
1119 Encoding::EIP712 => {
1120 Bits256::from_hex_str(EIP_712_PARALLEL_SIGNED_CALL_CONTRACT_TYPE_HASH)
1121 .unwrap()
1122 .0
1123 }
1124 }
1125 }
1126
1127 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
1128 let mut tokens: Vec<u8> = Vec::new();
1129 match encoding {
1130 Encoding::SRC16 => tokens.extend_from_slice(
1131 Bits256::from_hex_str(SRC_16_PARALLEL_SIGNED_CALL_CONTRACT_TYPE_HASH)
1132 .unwrap()
1133 .0
1134 .as_slice(),
1135 ),
1136 Encoding::EIP712 => tokens.extend_from_slice(
1137 Bits256::from_hex_str(EIP_712_PARALLEL_SIGNED_CALL_CONTRACT_TYPE_HASH)
1138 .unwrap()
1139 .0
1140 .as_slice(),
1141 ),
1142 }
1143
1144 tokens.extend_from_slice(fuel_u256_to_bytes(&self.nonce).as_slice());
1145 tokens
1146 .extend_from_slice(self.call_contract_args.struct_hash(encoding).as_slice());
1147
1148 keccak256(tokens)
1149 }
1150}
1151
1152pub const SRC_16_PARALLEL_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH: &str =
1153 "0x6e32a14f4ba8a2ed500508d524a5dc852052062ee2323ed1a564d344fffda461";
1154
1155pub const EIP_712_PARALLEL_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH: &str =
1156 "0xc74d58c126fe07446fe4ae31d63e02160ebe265cc44024b5227bacfdb31dd28b";
1157
1158impl SRC16Encode for ParallelMultiCallContractArgs {
1159 fn type_hash(encoding: Encoding) -> [u8; 32] {
1160 match encoding {
1161 Encoding::SRC16 => {
1162 Bits256::from_hex_str(
1163 SRC_16_PARALLEL_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH,
1164 )
1165 .unwrap()
1166 .0
1167 }
1168 Encoding::EIP712 => {
1169 Bits256::from_hex_str(
1170 EIP_712_PARALLEL_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH,
1171 )
1172 .unwrap()
1173 .0
1174 }
1175 }
1176 }
1177
1178 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
1179 let mut tokens: Vec<u8> = Vec::new();
1180 match encoding {
1181 Encoding::SRC16 => tokens.extend_from_slice(
1182 Bits256::from_hex_str(
1183 SRC_16_PARALLEL_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH,
1184 )
1185 .unwrap()
1186 .0
1187 .as_slice(),
1188 ),
1189 Encoding::EIP712 => tokens.extend_from_slice(
1190 Bits256::from_hex_str(
1191 EIP_712_PARALLEL_SIGNED_MULTI_CALL_CONTRACT_TYPE_HASH,
1192 )
1193 .unwrap()
1194 .0
1195 .as_slice(),
1196 ),
1197 }
1198
1199 tokens.extend_from_slice(fuel_u256_to_bytes(&self.nonce).as_slice());
1200
1201 let mut call_buffer: Vec<u8> = Vec::new();
1202 for call in self.call_contract_args {
1203 call_buffer.extend_from_slice(call.struct_hash(encoding.clone()).as_slice());
1204 }
1205 tokens.extend_from_slice(keccak256(call_buffer).as_slice());
1206
1207 keccak256(tokens)
1208 }
1209}
1210
1211pub const SRC_16_PARALLEL_REVOKE_TYPE_HASH: &str =
1212 "0xac7c930989abf28d71694ae7f327a130cdc1ef80040d94c6873cf0686024382d";
1213
1214pub const EIP_712_PARALLEL_REVOKE_TYPE_HASH: &str =
1215 "0x51c1376821126b4be9647fdbbf51877dd5a72c6a76e58fb957f37ac985962ea8";
1216
1217impl SRC16Encode for ParallelRevokeArgs {
1218 fn type_hash(encoding: Encoding) -> [u8; 32] {
1219 match encoding {
1220 Encoding::SRC16 => {
1221 Bits256::from_hex_str(SRC_16_PARALLEL_REVOKE_TYPE_HASH)
1222 .unwrap()
1223 .0
1224 }
1225 Encoding::EIP712 => {
1226 Bits256::from_hex_str(EIP_712_PARALLEL_REVOKE_TYPE_HASH)
1227 .unwrap()
1228 .0
1229 }
1230 }
1231 }
1232
1233 fn struct_hash(self, encoding: Encoding) -> [u8; 32] {
1234 let mut tokens: Vec<u8> = Vec::new();
1235 match encoding {
1236 Encoding::SRC16 => tokens.extend_from_slice(
1237 Bits256::from_hex_str(SRC_16_PARALLEL_REVOKE_TYPE_HASH)
1238 .unwrap()
1239 .0
1240 .as_slice(),
1241 ),
1242 Encoding::EIP712 => tokens.extend_from_slice(
1243 Bits256::from_hex_str(EIP_712_PARALLEL_REVOKE_TYPE_HASH)
1244 .unwrap()
1245 .0
1246 .as_slice(),
1247 ),
1248 }
1249
1250 tokens.extend_from_slice(fuel_u256_to_bytes(&self.nonce).as_slice());
1251
1252 keccak256(tokens)
1253 }
1254}