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
@@ -32,6 +34,8 @@ contract PegInContract is
3234
3335 /// @notice The version of the contract
3436 string constant public VERSION = "1.0.0 " ;
37+ /// @notice The name of the contract (used for EIP712)
38+ string constant public NAME = "PegInContract " ;
3539 Flyover.ProviderType constant private _PEG_TYPE = Flyover.ProviderType.PegIn;
3640 uint256 constant private _REFUND_ADDRESS_LENGTH = 21 ;
3741
@@ -90,6 +94,7 @@ contract PegInContract is
9094 ) external initializer {
9195 if (collateralManagement.code.length == 0 ) revert Flyover.NoContract (collateralManagement);
9296 __ReentrancyGuard_init ();
97+ __EIP712_init (NAME, VERSION);
9398 // Initialize EmergencyPause (includes AccessControl, Pausable, and grants PAUSER_ROLE)
9499 __EmergencyPause_init (0 , defaultAdmin);
95100 _bridge = IBridge (bridge);
@@ -285,6 +290,11 @@ contract PegInContract is
285290 return _hashPegInQuote (quote);
286291 }
287292
293+ /// @inheritdoc IPegIn
294+ function hashPegInQuoteEIP712 (Quotes.PegInQuote calldata quote ) external view override returns (bytes32 ) {
295+ return _hashPegInQuoteEIP712 (quote);
296+ }
297+
288298 /// @inheritdoc IPegIn
289299 function getQuoteStatus (bytes32 quoteHash ) external view override returns (PegInStates) {
290300 if (_reentrancyGuardEntered ()) revert ReentrancyGuardReentrantCall ();
@@ -465,8 +475,9 @@ contract PegInContract is
465475 if (_processedQuotes[quoteHash] == PegInStates.PROCESSED_QUOTE) {
466476 revert QuoteAlreadyProcessed (quoteHash);
467477 }
468- if (! SignatureValidator.verify (quote.liquidityProviderRskAddress, quoteHash, signature)) {
469- revert SignatureValidator.IncorrectSignature (quote.liquidityProviderRskAddress, quoteHash, signature);
478+ bytes32 eip712hash = _hashPegInQuoteEIP712 (quote);
479+ if (! SignatureValidator.verify (quote.liquidityProviderRskAddress, eip712hash, signature)) {
480+ revert SignatureValidator.IncorrectSignature (quote.liquidityProviderRskAddress, eip712hash, signature);
470481 }
471482 // the actual type in the RSKj node source code is a java int which is equivalent to int32
472483 if (height > uint256 (int (type (int32 ).max)) - 1 ) {
@@ -485,6 +496,26 @@ contract PegInContract is
485496 /// @param quote The peg in quote
486497 /// @return quoteHash The hash of the quote
487498 function _hashPegInQuote (Quotes.PegInQuote calldata quote ) private view returns (bytes32 ) {
499+ _validatePegInQuote (quote);
500+ return keccak256 (Quotes.encodeQuote (quote));
501+ }
502+
503+ /// @notice This function is used to hash a peg in quote using EIP712 specification
504+ /// @dev The function also validates the following:
505+ /// - The quote belongs to this contract
506+ /// - The quote destination is not the bridge contract
507+ /// - The quote BTC refund address is valid
508+ /// - The quote liquidity provider BTC address is valid
509+ /// - The quote total amount is greater than the bridge minimum peg in amount
510+ /// - The sum of the timestamp values is not greater than the maximum uint32 value
511+ /// @param quote The peg in quote
512+ /// @return quoteHash The hash struct to be combined with the domain separator
513+ function _hashPegInQuoteEIP712 (Quotes.PegInQuote calldata quote ) private view returns (bytes32 ) {
514+ _validatePegInQuote (quote);
515+ return _hashTypedDataV4 (Quotes.hashPegInQuoteEIP712 (quote));
516+ }
517+
518+ function _validatePegInQuote (Quotes.PegInQuote calldata quote ) private view {
488519 if (address (this ) != quote.lbcAddress) {
489520 revert Flyover.IncorrectContract (address (this ), quote.lbcAddress);
490521 }
@@ -504,7 +535,6 @@ contract PegInContract is
504535 if (type (uint32 ).max < uint64 (quote.agreementTimestamp) + uint64 (quote.timeForDeposit)) {
505536 revert Flyover.Overflow (type (uint32 ).max);
506537 }
507- return keccak256 (Quotes.encodeQuote (quote));
508538 }
509539
510540 /// @notice This function is used to determine if the liquidity provider should be penalized
0 commit comments