-
Notifications
You must be signed in to change notification settings - Fork 7
/
EIP712Lib.sol
131 lines (120 loc) · 4.72 KB
/
EIP712Lib.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import "../../domain/BosonConstants.sol";
import { ProtocolLib } from "../libs/ProtocolLib.sol";
/**
* @title EIP712Lib
*
* @dev Provides the domain separator and chain id.
*/
library EIP712Lib {
/**
* @notice Generates the domain separator hash.
* @dev Using the chainId as the salt enables the client to be active on one chain
* while a metatx is signed for a contract on another chain. That could happen if the client is,
* for instance, a metaverse scene that runs on one chain while the contracts it interacts with are deployed on another chain.
*
* @param _name - the name of the protocol
* @param _version - The version of the protocol
* @return the domain separator hash
*/
function buildDomainSeparator(string memory _name, string memory _version) internal view returns (bytes32) {
return
keccak256(
abi.encode(
EIP712_DOMAIN_TYPEHASH,
keccak256(bytes(_name)),
keccak256(bytes(_version)),
address(this),
block.chainid
)
);
}
/**
* @notice Recovers the Signer from the Signature components.
*
* Reverts if:
* - Signer is the zero address
*
* @param _user - the sender of the transaction
* @param _hashedMetaTx - hashed meta transaction
* @param _sigR - r part of the signer's signature
* @param _sigS - s part of the signer's signature
* @param _sigV - v part of the signer's signature
* @return true if signer is same as _user parameter
*/
function verify(
address _user,
bytes32 _hashedMetaTx,
bytes32 _sigR,
bytes32 _sigS,
uint8 _sigV
) internal returns (bool) {
// Ensure signature is unique
// See https://github.com/OpenZeppelin/openzeppelin-contracts/blob/04695aecbd4d17dddfd55de766d10e3805d6f42f/contracts/cryptography/ECDSA.sol#63
require(
uint256(_sigS) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 &&
(_sigV == 27 || _sigV == 28),
INVALID_SIGNATURE
);
address signer = ecrecover(toTypedMessageHash(_hashedMetaTx), _sigV, _sigR, _sigS);
require(signer != address(0), INVALID_SIGNATURE);
return signer == _user;
}
/**
* @notice Gets the domain separator from storage if matches with the chain id and diamond address, else, build new domain separator.
*
* @return the domain separator
*/
function getDomainSeparator() private returns (bytes32) {
ProtocolLib.ProtocolMetaTxInfo storage pmti = ProtocolLib.protocolMetaTxInfo();
uint256 cachedChainId = pmti.cachedChainId;
if (block.chainid == cachedChainId) {
return ProtocolLib.protocolMetaTxInfo().domainSeparator;
} else {
pmti.cachedChainId = block.chainid;
return buildDomainSeparator(PROTOCOL_NAME, PROTOCOL_VERSION);
}
}
/**
* @notice Generates EIP712 compatible message hash.
*
* @dev Accepts message hash and returns hash message in EIP712 compatible form
* so that it can be used to recover signer from signature signed using EIP712 formatted data
* https://eips.ethereum.org/EIPS/eip-712
* "\\x19" makes the encoding deterministic
* "\\x01" is the version byte to make it compatible to EIP-191
*
* @param _messageHash - the message hash
* @return the EIP712 compatible message hash
*/
function toTypedMessageHash(bytes32 _messageHash) internal returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", getDomainSeparator(), _messageHash));
}
/**
* @notice Gets the current message sender address from storage.
*
* @return the the current message sender address from storage
*/
function getCurrentSenderAddress() internal view returns (address) {
return ProtocolLib.protocolMetaTxInfo().currentSenderAddress;
}
/**
* @notice Returns the message sender address.
*
* @dev Could be msg.sender or the message sender address from storage (in case of meta transaction).
*
* @return the message sender address
*/
function msgSender() internal view returns (address) {
bool isItAMetaTransaction = ProtocolLib.protocolMetaTxInfo().isMetaTransaction;
// Get sender from the storage if this is a meta transaction
if (isItAMetaTransaction) {
address sender = getCurrentSenderAddress();
require(sender != address(0), INVALID_ADDRESS);
return sender;
} else {
return msg.sender;
}
}
}