1
- import BigInt
2
1
import CryptoSwift
3
2
import Foundation
3
+ import BigInt
4
4
import Core
5
5
6
- // TODO: Refactor me
7
-
8
- struct EIP712Domain : EIP712DomainHashable {
9
- let chainId : EIP712 . UInt256 ?
10
- let verifyingContract : EIP712 . Address
11
- }
12
-
13
- protocol EIP712DomainHashable : EIP712Hashable { }
14
-
15
- public struct SafeTx : EIP712Hashable {
16
- let to : EIP712 . Address
17
- let value : EIP712 . UInt256
18
- let data : EIP712 . Bytes
19
- let operation : EIP712 . UInt8
20
- let safeTxGas : EIP712 . UInt256
21
- let baseGas : EIP712 . UInt256
22
- let gasPrice : EIP712 . UInt256
23
- let gasToken : EIP712 . Address
24
- let refundReceiver : EIP712 . Address
25
- let nonce : EIP712 . UInt256
26
-
27
- 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 ) {
28
- self . to = to
29
- self . value = value
30
- self . data = data
31
- self . operation = operation
32
- self . safeTxGas = safeTxGas
33
- self . baseGas = baseGas
34
- self . gasPrice = gasPrice
35
- self . gasToken = gasToken
36
- self . refundReceiver = refundReceiver
37
- self . nonce = nonce
38
- }
39
-
40
- }
41
-
42
6
/// Protocol defines EIP712 struct encoding
43
7
public protocol EIP712Hashable {
44
8
var typehash : Data { get }
@@ -52,6 +16,15 @@ public class EIP712 {
52
16
public typealias Bytes = Data
53
17
}
54
18
19
+ public struct EIP712Domain : EIP712Hashable {
20
+ public let chainId : EIP712 . UInt256 ?
21
+ public let verifyingContract : EIP712 . Address
22
+ public init ( chainId: EIP712 . UInt256 ? , verifyingContract: EIP712 . Address ) {
23
+ self . chainId = chainId
24
+ self . verifyingContract = verifyingContract
25
+ }
26
+ }
27
+
55
28
public extension EIP712 . Address {
56
29
static var zero : Self {
57
30
EthereumAddress ( Data ( count: 20 ) ) !
@@ -114,19 +87,19 @@ public extension EIP712Hashable {
114
87
// MARK: - Default implementation
115
88
116
89
var typehash : Data {
117
- keccak256 ( encodeType ( ) )
90
+ Data ( encodeType ( ) . bytes ) . sha3 ( . keccak256 )
118
91
}
119
92
120
93
func hash( ) throws -> Data {
121
94
typealias SolidityValue = ( value: Any , type: ABI . Element . ParameterType )
122
- var parametrs : [ Data ] = [ self . typehash]
95
+ var parameters : [ Data ] = [ typehash]
123
96
for case let ( _, field) in Mirror ( reflecting: self ) . children {
124
97
let result : Data
125
98
switch field {
126
99
case let string as String :
127
- result = keccak256 ( string)
100
+ result = Data ( string. bytes ) . sha3 ( . keccak256 )
128
101
case let data as EIP712 . Bytes :
129
- result = keccak256 ( data)
102
+ result = data. sha3 ( . keccak256 )
130
103
case is EIP712 . UInt8 :
131
104
result = ABIEncoder . encodeSingleType ( type: . uint( bits: 8 ) , value: field as AnyObject ) !
132
105
case is EIP712 . UInt256 :
@@ -143,28 +116,54 @@ public extension EIP712Hashable {
143
116
}
144
117
}
145
118
guard result. count == 32 else { preconditionFailure ( " ABI encode error " ) }
146
- parametrs . append ( result)
119
+ parameters . append ( result)
147
120
}
148
- let encoded = parametrs. flatMap { $0. bytes }
149
- return keccak256 ( encoded)
121
+ return Data ( parameters. flatMap { $0. bytes } ) . sha3 ( . keccak256)
150
122
}
151
123
}
152
124
153
- // Encode functions
154
- func eip712encode( domainSeparator: EIP712Hashable , message: EIP712Hashable ) throws -> Data {
125
+ public func eip712encode( domainSeparator: EIP712Hashable , message: EIP712Hashable ) throws -> Data {
155
126
let data = try Data ( [ UInt8 ( 0x19 ) , UInt8 ( 0x01 ) ] ) + domainSeparator. hash ( ) + message. hash ( )
156
- return keccak256 ( data)
127
+ return data. sha3 ( . keccak256 )
157
128
}
158
129
159
- // MARK: - keccak256
160
- private func keccak256( _ data: [ UInt8 ] ) -> Data {
161
- Data ( SHA3 ( variant: . keccak256) . calculate ( for: data) )
162
- }
130
+ // MARK: - Gnosis Safe Transaction model
163
131
164
- private func keccak256( _ string: String ) -> Data {
165
- keccak256 ( Array ( string. utf8) )
166
- }
132
+ /// Gnosis Safe Transaction.
133
+ /// https://docs.gnosis-safe.io/tutorials/tutorial_tx_service_initiate_sign
134
+ public struct SafeTx : EIP712Hashable {
135
+ /// Checksummed address
136
+ let to : EIP712 . Address
137
+ /// Value in wei
138
+ let value : EIP712 . UInt256
139
+ /// 0x prefixed hex string
140
+ let data : EIP712 . Bytes
141
+ /// `0` CALL, `1` DELEGATE_CALL
142
+ let operation : EIP712 . UInt8
143
+ /// Token address, **must be checksummed**, (held by the Safe) to be used as a refund to the sender, if `null` is Ether
144
+ let gasToken : EIP712 . Address
145
+ /// Max gas to use in the transaction
146
+ let safeTxGas : EIP712 . UInt256
147
+ /// Gast costs not related to the transaction execution (signature check, refund payment...)
148
+ let baseGas : EIP712 . UInt256
149
+ /// Gas price used for the refund calculation
150
+ let gasPrice : EIP712 . UInt256
151
+ /// Checksummed address of receiver of gas payment (or `null` if tx.origin)
152
+ let refundReceiver : EIP712 . Address
153
+ /// Nonce of the Safe, transaction cannot be executed until Safe's nonce is not equal to this nonce
154
+ let nonce : EIP712 . UInt256
155
+
156
+ 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 ) {
157
+ self . to = to
158
+ self . value = value
159
+ self . data = data
160
+ self . operation = operation
161
+ self . safeTxGas = safeTxGas
162
+ self . baseGas = baseGas
163
+ self . gasPrice = gasPrice
164
+ self . gasToken = gasToken
165
+ self . refundReceiver = refundReceiver
166
+ self . nonce = nonce
167
+ }
167
168
168
- private func keccak256( _ data: Data ) -> Data {
169
- keccak256 ( data. bytes)
170
169
}
0 commit comments