11// SPDX-License-Identifier: MIT
22pragma solidity 0.8.25 ;
33
4+ import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol " ;
45import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol " ;
56import {BtcUtils} from "@rsksmart/btc-transaction-solidity-helper/contracts/BtcUtils.sol " ;
67import {OpCodes} from "@rsksmart/btc-transaction-solidity-helper/contracts/OpCodes.sol " ;
@@ -19,6 +20,7 @@ import {SignatureValidator} from "./libraries/SignatureValidator.sol";
1920contract PegInContract is
2021 EmergencyPause ,
2122 ReentrancyGuardUpgradeable ,
23+ EIP712Upgradeable ,
2224 IPegIn
2325{
2426 /// @notice This struct is used to store the information of a call on behalf of the user
@@ -31,6 +33,8 @@ contract PegInContract is
3133
3234 /// @notice The version of the contract
3335 string constant public VERSION = "1.0.0 " ;
36+ /// @notice The name of the contract (used for EIP712)
37+ string constant public NAME = "PegInContract " ;
3438 Flyover.ProviderType constant private _PEG_TYPE = Flyover.ProviderType.PegIn;
3539 uint256 constant private _REFUND_ADDRESS_LENGTH = 21 ;
3640
@@ -94,6 +98,7 @@ contract PegInContract is
9498 ) external initializer {
9599 if (collateralManagement.code.length == 0 ) revert Flyover.NoContract (collateralManagement);
96100 __ReentrancyGuard_init ();
101+ __EIP712_init (NAME, VERSION);
97102 // Initialize EmergencyPause (includes AccessControl, Pausable, and grants PAUSER_ROLE)
98103 __EmergencyPause_init (0 , defaultAdmin);
99104 _bridge = IBridge (bridge);
@@ -289,6 +294,11 @@ contract PegInContract is
289294 return _hashPegInQuote (quote);
290295 }
291296
297+ /// @inheritdoc IPegIn
298+ function hashPegInQuoteEIP712 (Quotes.PegInQuote calldata quote ) external view override returns (bytes32 ) {
299+ return _hashPegInQuoteEIP712 (quote);
300+ }
301+
292302 /// @inheritdoc IPegIn
293303 function getQuoteStatus (bytes32 quoteHash ) external view override returns (PegInStates) {
294304 if (_reentrancyGuardEntered ()) revert ReentrancyGuardReentrantCall ();
@@ -469,8 +479,9 @@ contract PegInContract is
469479 if (_processedQuotes[quoteHash] == PegInStates.PROCESSED_QUOTE) {
470480 revert QuoteAlreadyProcessed (quoteHash);
471481 }
472- if (! SignatureValidator.verify (quote.liquidityProviderRskAddress, quoteHash, signature)) {
473- revert SignatureValidator.IncorrectSignature (quote.liquidityProviderRskAddress, quoteHash, signature);
482+ bytes32 eip712hash = _hashPegInQuoteEIP712 (quote);
483+ if (! SignatureValidator.verify (quote.liquidityProviderRskAddress, eip712hash, signature)) {
484+ revert SignatureValidator.IncorrectSignature (quote.liquidityProviderRskAddress, eip712hash, signature);
474485 }
475486 // the actual type in the RSKj node source code is a java int which is equivalent to int32
476487 if (height > uint256 (int (type (int32 ).max)) - 1 ) {
@@ -489,6 +500,29 @@ contract PegInContract is
489500 /// @param quote The peg in quote
490501 /// @return quoteHash The hash of the quote
491502 function _hashPegInQuote (Quotes.PegInQuote calldata quote ) private view returns (bytes32 ) {
503+ _validatePegInQuote (quote);
504+ return keccak256 (Quotes.encodeQuote (quote));
505+ }
506+
507+ /// @notice This function is used to hash a peg in quote using EIP712 specification
508+ /// @dev The function also validates the following:
509+ /// - The quote belongs to this contract
510+ /// - The quote destination is not the bridge contract
511+ /// - The quote BTC refund address is valid
512+ /// - The quote liquidity provider BTC address is valid
513+ /// - The quote total amount is greater than the bridge minimum peg in amount
514+ /// - The sum of the timestamp values is not greater than the maximum uint32 value
515+ /// @param quote The peg in quote
516+ /// @return quoteHash The hash struct to be combined with the domain separator
517+ function _hashPegInQuoteEIP712 (Quotes.PegInQuote calldata quote ) private view returns (bytes32 ) {
518+ _validatePegInQuote (quote);
519+ return _hashTypedDataV4 (Quotes.hashPegInQuoteEIP712 (quote));
520+ }
521+
522+ function _validatePegInQuote (Quotes.PegInQuote calldata quote ) private view {
523+ if (quote.chainId != block .chainid ) {
524+ revert Flyover.InvalidChainId (block .chainid , quote.chainId);
525+ }
492526 if (address (this ) != quote.lbcAddress) {
493527 revert Flyover.IncorrectContract (address (this ), quote.lbcAddress);
494528 }
@@ -508,7 +542,6 @@ contract PegInContract is
508542 if (type (uint32 ).max < uint64 (quote.agreementTimestamp) + uint64 (quote.timeForDeposit)) {
509543 revert Flyover.Overflow (type (uint32 ).max);
510544 }
511- return keccak256 (Quotes.encodeQuote (quote));
512545 }
513546
514547 /// @notice This function is used to determine if the liquidity provider should be penalized
0 commit comments