@@ -31,60 +31,8 @@ public extension EIP712.Address {
31
31
}
32
32
}
33
33
34
+ // MARK: - Default implementation for EIP712Hashable
34
35
public extension EIP712Hashable {
35
- private var name : String {
36
- let fullName = " \( Self . self) "
37
- let name = fullName. components ( separatedBy: " . " ) . last ?? fullName
38
- return name
39
- }
40
-
41
- private func dependencies( ) -> [ EIP712Hashable ] {
42
- Mirror ( reflecting: self ) . children
43
- . compactMap { $0. value as? EIP712Hashable }
44
- . flatMap { [ $0] + $0. dependencies ( ) }
45
- }
46
-
47
- private func encodePrimaryType( ) -> String {
48
- let parametrs : [ String ] = Mirror ( reflecting: self ) . children. compactMap { key, value in
49
- guard let key = key else { return nil }
50
-
51
- func checkIfValueIsNil( value: Any ) -> Bool {
52
- let mirror = Mirror ( reflecting: value)
53
- if mirror. displayStyle == . optional {
54
- if mirror. children. count == 0 {
55
- return true
56
- }
57
- }
58
-
59
- return false
60
- }
61
-
62
- guard !checkIfValueIsNil( value: value) else { return nil }
63
-
64
- let typeName : String
65
- switch value {
66
- case is EIP712 . UInt8 : typeName = " uint8 "
67
- case is EIP712 . UInt256 : typeName = " uint256 "
68
- case is EIP712 . Address : typeName = " address "
69
- case is EIP712 . Bytes : typeName = " bytes "
70
- case let hashable as EIP712Hashable : typeName = hashable. name
71
- default : typeName = " \( type ( of: value) ) " . lowercased ( )
72
- }
73
- return typeName + " " + key
74
- }
75
- return self . name + " ( " + parametrs. joined ( separator: " , " ) + " ) "
76
- }
77
-
78
- func encodeType( ) -> String {
79
- let dependencies = self . dependencies ( ) . map { $0. encodePrimaryType ( ) }
80
- let selfPrimaryType = self . encodePrimaryType ( )
81
-
82
- let result = Set ( dependencies) . filter { $0 != selfPrimaryType }
83
- return selfPrimaryType + result. sorted ( ) . joined ( )
84
- }
85
-
86
- // MARK: - Default implementation
87
-
88
36
var typehash : Data {
89
37
Data ( encodeType ( ) . bytes) . sha3 ( . keccak256)
90
38
}
@@ -126,11 +74,74 @@ public func eip712encode(domainSeparator: EIP712Hashable, message: EIP712Hashabl
126
74
return data. sha3 ( . keccak256)
127
75
}
128
76
77
+ // MARK: - Additional private and public extensions with support members
78
+
79
+ public extension EIP712Hashable {
80
+ func encodeType( ) -> String {
81
+ let dependencies = dependencies ( ) . map { $0. encodePrimaryType ( ) }
82
+ let selfPrimaryType = encodePrimaryType ( )
83
+
84
+ let result = Set ( dependencies) . filter { $0 != selfPrimaryType }
85
+ return selfPrimaryType + result. sorted ( ) . joined ( )
86
+ }
87
+ }
88
+
89
+ fileprivate extension EIP712Hashable {
90
+ var name : String {
91
+ let fullName = " \( Self . self) "
92
+ let name = fullName. components ( separatedBy: " . " ) . last ?? fullName
93
+ return name
94
+ }
95
+
96
+ func dependencies( ) -> [ EIP712Hashable ] {
97
+ Mirror ( reflecting: self ) . children
98
+ . compactMap { $0. value as? EIP712Hashable }
99
+ . flatMap { [ $0] + $0. dependencies ( ) }
100
+ }
101
+
102
+ func encodePrimaryType( ) -> String {
103
+ let parametrs : [ String ] = Mirror ( reflecting: self ) . children. compactMap { key, value in
104
+ guard let key = key else { return nil }
105
+
106
+ func checkIfValueIsNil( value: Any ) -> Bool {
107
+ let mirror = Mirror ( reflecting: value)
108
+ if mirror. displayStyle == . optional {
109
+ if mirror. children. count == 0 {
110
+ return true
111
+ }
112
+ }
113
+
114
+ return false
115
+ }
116
+
117
+ guard !checkIfValueIsNil( value: value) else { return nil }
118
+
119
+ let typeName : String
120
+ switch value {
121
+ case is EIP712 . UInt8 : typeName = " uint8 "
122
+ case is EIP712 . UInt256 : typeName = " uint256 "
123
+ case is EIP712 . Address : typeName = " address "
124
+ case is EIP712 . Bytes : typeName = " bytes "
125
+ case let hashable as EIP712Hashable : typeName = hashable. name
126
+ default : typeName = " \( type ( of: value) ) " . lowercased ( )
127
+ }
128
+ return typeName + " " + key
129
+ }
130
+ return self . name + " ( " + parametrs. joined ( separator: " , " ) + " ) "
131
+ }
132
+ }
133
+
129
134
// MARK: - Gnosis Safe Transaction model
130
135
131
136
/// Gnosis Safe Transaction.
132
137
/// https://docs.gnosis-safe.io/tutorials/tutorial_tx_service_initiate_sign
133
- public struct SafeTx : EIP712Hashable {
138
+ ///
139
+ /// Note for web3swift developers: **DO NOT CHANGE THE ORDER OF VARIABLES**.
140
+ ///
141
+ /// Changing the order will result in a different hash.
142
+ /// Order must match the implementation of hash calculation in
143
+ /// [`GnosisSafe.sol`](https://github.com/safe-global/safe-contracts/blob/main/contracts/GnosisSafe.sol#L126).
144
+ public struct GnosisSafeTx : EIP712Hashable {
134
145
/// Checksummed address
135
146
let to : EIP712 . Address
136
147
/// Value in wei
@@ -139,20 +150,29 @@ public struct SafeTx: EIP712Hashable {
139
150
let data : EIP712 . Bytes
140
151
/// `0` CALL, `1` DELEGATE_CALL
141
152
let operation : EIP712 . UInt8
142
- /// Token address, **must be checksummed**, (held by the Safe) to be used as a refund to the sender, if `null` is Ether
143
- let gasToken : EIP712 . Address
144
153
/// Max gas to use in the transaction
145
154
let safeTxGas : EIP712 . UInt256
146
155
/// Gast costs not related to the transaction execution (signature check, refund payment...)
147
156
let baseGas : EIP712 . UInt256
148
157
/// Gas price used for the refund calculation
149
158
let gasPrice : EIP712 . UInt256
159
+ /// Token address, **must be checksummed**, (held by the Safe) to be used as a refund to the sender, if `null` is Ether
160
+ let gasToken : EIP712 . Address
150
161
/// Checksummed address of receiver of gas payment (or `null` if tx.origin)
151
162
let refundReceiver : EIP712 . Address
152
163
/// Nonce of the Safe, transaction cannot be executed until Safe's nonce is not equal to this nonce
153
164
let nonce : EIP712 . UInt256
154
165
155
- public init ( to: EIP712 . Address , value: EIP712 . UInt256 , data: EIP712 . Bytes , operation: EIP712 . UInt8 , safeTxGas: EIP712 . UInt256 , baseGas: EIP712 . UInt256 , gasPrice: EIP712 . UInt256 , gasToken: EIP712 . Address , refundReceiver: EIP712 . Address , nonce: EIP712 . UInt256 ) {
166
+ public init ( to: EIP712 . Address ,
167
+ value: EIP712 . UInt256 ,
168
+ data: EIP712 . Bytes ,
169
+ operation: EIP712 . UInt8 ,
170
+ safeTxGas: EIP712 . UInt256 ,
171
+ baseGas: EIP712 . UInt256 ,
172
+ gasPrice: EIP712 . UInt256 ,
173
+ gasToken: EIP712 . Address ,
174
+ refundReceiver: EIP712 . Address ,
175
+ nonce: EIP712 . UInt256 ) {
156
176
self . to = to
157
177
self . value = value
158
178
self . data = data
0 commit comments