-
-
Notifications
You must be signed in to change notification settings - Fork 56
/
EIP712DomainSeparator.vy
167 lines (141 loc) · 6.11 KB
/
EIP712DomainSeparator.vy
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# @version ^0.3.9
"""
@title EIP-712 Domain Separator
@custom:contract-name EIP712DomainSeparator
@license GNU Affero General Public License v3.0
@author pcaversaccio
@notice These functions are part of EIP-712: https://eips.ethereum.org/EIPS/eip-712.
These functions implement the version of encoding known
as "v4" as implemented by the JSON-RPC method:
https://docs.metamask.io/guide/signing-data.html#sign-typed-data-v4.
In addition, this contract also implements EIP-5267:
https://eips.ethereum.org/EIPS/eip-5267.
The implementation is inspired by OpenZeppelin's implementation here:
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/draft-EIP712.sol.
"""
# @dev We import and implement the `IERC5267` interface,
# which is written using standard Vyper syntax.
import interfaces.IERC5267 as IERC5267
implements: IERC5267
# @dev The 32-byte type hash for the EIP-712 domain separator.
_TYPE_HASH: constant(bytes32) = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
# @dev Caches the domain separator as an `immutable`
# value, but also stores the corresponding chain ID
# to invalidate the cached domain separator if the
# chain ID changes.
_CACHED_DOMAIN_SEPARATOR: immutable(bytes32)
_CACHED_CHAIN_ID: immutable(uint256)
# @dev Caches `self` to `immutable` storage to avoid
# potential issues if a vanilla contract is used in
# a `delegatecall` context.
_CACHED_SELF: immutable(address)
# @dev `immutable` variables to store the (hashed)
# name and (hashed) version during contract creation.
_NAME: immutable(String[50])
_HASHED_NAME: immutable(bytes32)
_VERSION: immutable(String[20])
_HASHED_VERSION: immutable(bytes32)
# @dev May be emitted to signal that the domain could
# have changed.
event EIP712DomainChanged:
pass
@external
@payable
def __init__(name_: String[50], version_: String[20]):
"""
@dev Initialises the domain separator and the parameter caches.
To omit the opcodes for checking the `msg.value` in the
creation-time EVM bytecode, the constructor is declared as
`payable`.
@notice The definition of the domain separator can be found here:
https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator.
Since the Vyper design requires strings of fixed size,
we arbitrarily set the maximum length for `name` to 50
characters and `version` to 20 characters.
@param name_ The maximum 50-character user-readable string name
of the signing domain, i.e. the name of the dApp or protocol.
@param version_ The maximum 20-character current main version of
the signing domain. Signatures from different versions are
not compatible.
"""
_NAME = name_
_VERSION = version_
_HASHED_NAME = keccak256(name_)
_HASHED_VERSION = keccak256(version_)
_CACHED_DOMAIN_SEPARATOR = self._build_domain_separator()
_CACHED_CHAIN_ID = chain.id
_CACHED_SELF = self
@external
@view
def domain_separator_v4() -> bytes32:
"""
@dev Returns the domain separator for the current chain.
@return bytes32 The 32-byte domain separator.
"""
return self._domain_separator_v4()
@external
@view
def hash_typed_data_v4(struct_hash: bytes32) -> bytes32:
"""
@dev Returns the hash of the fully encoded EIP-712
message for this domain.
@notice The definition of the hashed struct can be found here:
https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.
@param struct_hash The 32-byte hashed struct.
@return bytes32 The 32-byte fully encoded EIP712
message hash for this domain.
"""
return self._to_typed_data_hash(self._domain_separator_v4(), struct_hash)
@external
@view
def eip712Domain() -> (bytes1, String[50], String[20], uint256, address, bytes32, DynArray[uint256, 128]):
"""
@dev Returns the fields and values that describe the domain
separator used by this contract for EIP-712 signatures.
@notice The bits in the 1-byte bit map are read from the least
significant to the most significant, and fields are indexed
in the order that is specified by EIP-712, identical to the
order in which they are listed in the function type.
@return bytes1 The 1-byte bit map where bit `i` is set to 1
if and only if domain field `i` is present (`0 ≤ i ≤ 4`).
@return String The maximum 50-character user-readable string name
of the signing domain, i.e. the name of the dApp or protocol.
@return String The maximum 20-character current main version of
the signing domain. Signatures from different versions are
not compatible.
@return uint256 The 32-byte EIP-155 chain ID.
@return address The 20-byte address of the verifying contract.
@return bytes32 The 32-byte disambiguation salt for the protocol.
@return DynArray The 32-byte array of EIP-712 extensions.
"""
# Note that `\x0f` equals `01111`.
return (convert(b"\x0f", bytes1), _NAME, _VERSION, chain.id, self, empty(bytes32), empty(DynArray[uint256, 128]))
@internal
@view
def _domain_separator_v4() -> bytes32:
"""
@dev An `internal` helper function that returns the domain separator
for the current chain.
@return bytes32 The 32-byte domain separator.
"""
if (self == _CACHED_SELF and chain.id == _CACHED_CHAIN_ID):
return _CACHED_DOMAIN_SEPARATOR
else:
return self._build_domain_separator()
@internal
@view
def _build_domain_separator() -> bytes32:
"""
@dev Builds the domain separator for the current chain.
@return bytes32 The 32-byte domain separator.
"""
return keccak256(_abi_encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, chain.id, self))
@internal
@pure
def _to_typed_data_hash(domain_separator: bytes32, struct_hash: bytes32) -> bytes32:
"""
@dev Sourced from {ECDSA-to_typed_data_hash}.
@notice See {ECDSA-to_typed_data_hash} for the
function docstring.
"""
return keccak256(concat(b"\x19\x01", domain_separator, struct_hash))