Skip to content

Commit 1fa4b47

Browse files
authored
fix: eip1559 type transaction signing and sending (#147)
1 parent 58da054 commit 1fa4b47

File tree

7 files changed

+336
-46
lines changed

7 files changed

+336
-46
lines changed

README.md

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@ targets: [
9494
.target(
9595
name: "MyProject",
9696
dependencies: [
97-
.product(name: "Web3", package: "Web3"),
98-
.product(name: "Web3PromiseKit", package: "Web3"),
99-
.product(name: "Web3ContractABI", package: "Web3"),
97+
.product(name: "Web3", package: "Web3.swift"),
98+
.product(name: "Web3PromiseKit", package: "Web3.swift"),
99+
.product(name: "Web3ContractABI", package: "Web3.swift"),
100100
]
101101
),
102102
.testTarget(
@@ -333,12 +333,16 @@ let myPrivateKey = try EthereumPrivateKey(hexPrivateKey: "...")
333333
firstly {
334334
web3.eth.getTransactionCount(address: myPrivateKey.address, block: .latest)
335335
}.then { nonce in
336-
try contract.transfer(to: EthereumAddress(hex: "0x3edB3b95DDe29580FFC04b46A68a31dD46106a4a", eip55: true), value: 100000).createTransaction(
336+
try contract.transfer(to: EthereumAddress(hex: "0x3edB3b95DDe29580FFC04b46A68a31dD46106a4a", eip55: true), value: 100000).createTransaction(
337337
nonce: nonce,
338+
gasPrice: EthereumQuantity(quantity: 21.gwei),
339+
maxFeePerGas: nil,
340+
maxPriorityFeePerGas: nil,
341+
gasLimit: 100000,
338342
from: myPrivateKey.address,
339343
value: 0,
340-
gas: 100000,
341-
gasPrice: EthereumQuantity(quantity: 21.gwei)
344+
accessList: [:],
345+
transactionType: .legacy
342346
)!.sign(with: myPrivateKey).promise
343347
}.then { tx in
344348
web3.eth.sendRawTransaction(transaction: tx)
@@ -353,12 +357,16 @@ let myAddress = try EthereumAddress(hex: "0x1f04ef7263804fafb839f0d04e2b5a6a1a57
353357
firstly {
354358
web3.eth.getTransactionCount(address: myAddress, block: .latest)
355359
}.then { nonce in
356-
try contract.transfer(to: EthereumAddress(hex: "0x3edB3b95DDe29580FFC04b46A68a31dD46106a4a", eip55: true), value: 100000).send(
360+
try contract.transfer(to: EthereumAddress(hex: "0x3edB3b95DDe29580FFC04b46A68a31dD46106a4a", eip55: true), value: 100000).send(
357361
nonce: nonce,
362+
gasPrice: EthereumQuantity(quantity: 21.gwei),
363+
maxFeePerGas: nil,
364+
maxPriorityFeePerGas: nil,
365+
gasLimit: 150000,
358366
from: myAddress,
359367
value: 0,
360-
gas: 150000,
361-
gasPrice: EthereumQuantity(quantity: 21.gwei)
368+
accessList: [:],
369+
transactionType: .legacy
362370
)
363371
}.done { txHash in
364372
print(txHash)
@@ -394,7 +402,17 @@ firstly {
394402

395403
// Send some tokens to another address (locally signing the transaction)
396404
let myPrivateKey = try EthereumPrivateKey(hexPrivateKey: "...")
397-
guard let transaction = contract["transfer"]?(EthereumAddress.testAddress, BigUInt(100000)).createTransaction(nonce: 0, from: myPrivateKey.address, value: 0, gas: 150000, gasPrice: EthereumQuantity(quantity: 21.gwei)) else {
405+
guard let transaction = contract["transfer"]?(EthereumAddress.testAddress, BigUInt(100000)).createTransaction(
406+
nonce: 0,
407+
gasPrice: EthereumQuantity(quantity: 21.gwei),
408+
maxFeePerGas: nil,
409+
maxPriorityFeePerGas: nil,
410+
gasLimit: 150000,
411+
from: myPrivateKey.address,
412+
value: 0,
413+
accessList: [:],
414+
transactionType: .legacy
415+
)) else {
398416
return
399417
}
400418
let signedTx = try transaction.sign(with: myPrivateKey)

Sources/ContractABI/Contract/SolidityInvocation.swift

Lines changed: 194 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77

88
import Foundation
9+
import Collections
910
#if !Web3CocoaPods
1011
import Web3
1112
#endif
@@ -32,13 +33,34 @@ public protocol SolidityInvocation {
3233
func createCall() -> EthereumCall?
3334

3435
/// Generates an EthereumTransaction object
35-
func createTransaction(nonce: EthereumQuantity?, from: EthereumAddress, value: EthereumQuantity?, gas: EthereumQuantity, gasPrice: EthereumQuantity?) -> EthereumTransaction?
36+
func createTransaction(
37+
nonce: EthereumQuantity?,
38+
gasPrice: EthereumQuantity?,
39+
maxFeePerGas: EthereumQuantity?,
40+
maxPriorityFeePerGas: EthereumQuantity?,
41+
gasLimit: EthereumQuantity?,
42+
from: EthereumAddress?,
43+
value: EthereumQuantity?,
44+
accessList: OrderedDictionary<EthereumAddress, [EthereumData]>,
45+
transactionType: EthereumTransaction.TransactionType
46+
) -> EthereumTransaction?
3647

3748
/// Read data from the blockchain. Only available for constant functions.
3849
func call(block: EthereumQuantityTag, completion: @escaping ([String: Any]?, Error?) -> Void)
3950

4051
/// Write data to the blockchain. Only available for non-constant functions.
41-
func send(nonce: EthereumQuantity?, from: EthereumAddress, value: EthereumQuantity?, gas: EthereumQuantity, gasPrice: EthereumQuantity?, completion: @escaping (EthereumData?, Error?) -> Void)
52+
func send(
53+
nonce: EthereumQuantity?,
54+
gasPrice: EthereumQuantity?,
55+
maxFeePerGas: EthereumQuantity?,
56+
maxPriorityFeePerGas: EthereumQuantity?,
57+
gasLimit: EthereumQuantity?,
58+
from: EthereumAddress,
59+
value: EthereumQuantity?,
60+
accessList: OrderedDictionary<EthereumAddress, [EthereumData]>,
61+
transactionType: EthereumTransaction.TransactionType,
62+
completion: @escaping (EthereumData?, Error?) -> Void
63+
)
4264

4365
/// Estimate how much gas is needed to execute this transaction.
4466
func estimateGas(from: EthereumAddress?, gas: EthereumQuantity?, value: EthereumQuantity?, completion: @escaping (EthereumQuantity?, Error?) -> Void)
@@ -78,7 +100,18 @@ public struct SolidityReadInvocation: SolidityInvocation {
78100
handler.call(call, outputs: outputs, block: block, completion: completion)
79101
}
80102

81-
public func send(nonce: EthereumQuantity? = nil, from: EthereumAddress, value: EthereumQuantity?, gas: EthereumQuantity, gasPrice: EthereumQuantity?, completion: @escaping (EthereumData?, Error?) -> Void) {
103+
public func send(
104+
nonce: EthereumQuantity?,
105+
gasPrice: EthereumQuantity?,
106+
maxFeePerGas: EthereumQuantity?,
107+
maxPriorityFeePerGas: EthereumQuantity?,
108+
gasLimit: EthereumQuantity?,
109+
from: EthereumAddress,
110+
value: EthereumQuantity?,
111+
accessList: OrderedDictionary<EthereumAddress, [EthereumData]>,
112+
transactionType: EthereumTransaction.TransactionType,
113+
completion: @escaping (EthereumData?, Error?) -> Void
114+
) {
82115
completion(nil, InvocationError.invalidInvocation)
83116
}
84117

@@ -88,7 +121,17 @@ public struct SolidityReadInvocation: SolidityInvocation {
88121
return EthereumCall(from: nil, to: to, gas: nil, gasPrice: nil, value: nil, data: data)
89122
}
90123

91-
public func createTransaction(nonce: EthereumQuantity?, from: EthereumAddress, value: EthereumQuantity?, gas: EthereumQuantity, gasPrice: EthereumQuantity?) -> EthereumTransaction? {
124+
public func createTransaction(
125+
nonce: EthereumQuantity?,
126+
gasPrice: EthereumQuantity?,
127+
maxFeePerGas: EthereumQuantity?,
128+
maxPriorityFeePerGas: EthereumQuantity?,
129+
gasLimit: EthereumQuantity?,
130+
from: EthereumAddress?,
131+
value: EthereumQuantity?,
132+
accessList: OrderedDictionary<EthereumAddress, [EthereumData]>,
133+
transactionType: EthereumTransaction.TransactionType
134+
) -> EthereumTransaction? {
92135
return nil
93136
}
94137

@@ -109,11 +152,34 @@ public struct SolidityPayableInvocation: SolidityInvocation {
109152
self.parameters = zip(parameters, method.inputs).map { SolidityWrappedValue(value: $0, type: $1.type) }
110153
self.handler = handler
111154
}
112-
113-
public func createTransaction(nonce: EthereumQuantity? = nil, from: EthereumAddress, value: EthereumQuantity?, gas: EthereumQuantity, gasPrice: EthereumQuantity?) -> EthereumTransaction? {
155+
156+
public func createTransaction(
157+
nonce: EthereumQuantity? = nil,
158+
gasPrice: EthereumQuantity? = nil,
159+
maxFeePerGas: EthereumQuantity? = nil,
160+
maxPriorityFeePerGas: EthereumQuantity? = nil,
161+
gasLimit: EthereumQuantity? = nil,
162+
from: EthereumAddress? = nil,
163+
value: EthereumQuantity? = nil,
164+
accessList: OrderedDictionary<EthereumAddress, [EthereumData]> = [:],
165+
transactionType: EthereumTransaction.TransactionType = .legacy
166+
) -> EthereumTransaction? {
114167
guard let data = encodeABI() else { return nil }
115168
guard let to = handler.address else { return nil }
116-
return EthereumTransaction(nonce: nonce, gasPrice: gasPrice, gasLimit: gas, from: from, to: to, value: value ?? 0, data: data)
169+
170+
return EthereumTransaction(
171+
nonce: nonce,
172+
gasPrice: gasPrice,
173+
maxFeePerGas: maxFeePerGas,
174+
maxPriorityFeePerGas: maxPriorityFeePerGas,
175+
gasLimit: gasLimit,
176+
from: from,
177+
to: to,
178+
value: value,
179+
data: data,
180+
accessList: accessList,
181+
transactionType: transactionType
182+
)
117183
}
118184

119185
public func createCall() -> EthereumCall? {
@@ -124,12 +190,33 @@ public struct SolidityPayableInvocation: SolidityInvocation {
124190
completion(nil, InvocationError.invalidInvocation)
125191
}
126192

127-
public func send(nonce: EthereumQuantity? = nil, from: EthereumAddress, value: EthereumQuantity?, gas: EthereumQuantity, gasPrice: EthereumQuantity?, completion: @escaping (EthereumData?, Error?) -> Void) {
193+
public func send(
194+
nonce: EthereumQuantity? = nil,
195+
gasPrice: EthereumQuantity? = nil,
196+
maxFeePerGas: EthereumQuantity? = nil,
197+
maxPriorityFeePerGas: EthereumQuantity? = nil,
198+
gasLimit: EthereumQuantity? = nil,
199+
from: EthereumAddress,
200+
value: EthereumQuantity? = nil,
201+
accessList: OrderedDictionary<EthereumAddress, [EthereumData]> = [:],
202+
transactionType: EthereumTransaction.TransactionType = .legacy,
203+
completion: @escaping (EthereumData?, Error?) -> Void
204+
) {
128205
guard handler.address != nil else {
129206
completion(nil, InvocationError.contractNotDeployed)
130207
return
131208
}
132-
guard let transaction = createTransaction(nonce: nonce, from: from, value: value, gas: gas, gasPrice: gasPrice) else {
209+
guard let transaction = createTransaction(
210+
nonce: nonce,
211+
gasPrice: gasPrice,
212+
maxFeePerGas: maxFeePerGas,
213+
maxPriorityFeePerGas: maxPriorityFeePerGas,
214+
gasLimit: gasLimit,
215+
from: from,
216+
value: value,
217+
accessList: accessList,
218+
transactionType: transactionType
219+
) else {
133220
completion(nil, InvocationError.encodingError)
134221
return
135222
}
@@ -152,10 +239,33 @@ public struct SolidityNonPayableInvocation: SolidityInvocation {
152239
self.handler = handler
153240
}
154241

155-
public func createTransaction(nonce: EthereumQuantity? = nil, from: EthereumAddress, value: EthereumQuantity?, gas: EthereumQuantity, gasPrice: EthereumQuantity?) -> EthereumTransaction? {
242+
public func createTransaction(
243+
nonce: EthereumQuantity? = nil,
244+
gasPrice: EthereumQuantity? = nil,
245+
maxFeePerGas: EthereumQuantity? = nil,
246+
maxPriorityFeePerGas: EthereumQuantity? = nil,
247+
gasLimit: EthereumQuantity? = nil,
248+
from: EthereumAddress? = nil,
249+
value: EthereumQuantity? = nil,
250+
accessList: OrderedDictionary<EthereumAddress, [EthereumData]> = [:],
251+
transactionType: EthereumTransaction.TransactionType = .legacy
252+
) -> EthereumTransaction? {
156253
guard let data = encodeABI() else { return nil }
157254
guard let to = handler.address else { return nil }
158-
return EthereumTransaction(nonce: nonce, gasPrice: gasPrice, gasLimit: gas, from: from, to: to, value: value ?? 0, data: data)
255+
256+
return EthereumTransaction(
257+
nonce: nonce,
258+
gasPrice: gasPrice,
259+
maxFeePerGas: maxFeePerGas,
260+
maxPriorityFeePerGas: maxPriorityFeePerGas,
261+
gasLimit: gasLimit,
262+
from: from,
263+
to: to,
264+
value: value,
265+
data: data,
266+
accessList: accessList,
267+
transactionType: transactionType
268+
)
159269
}
160270

161271
public func createCall() -> EthereumCall? {
@@ -166,12 +276,33 @@ public struct SolidityNonPayableInvocation: SolidityInvocation {
166276
completion(nil, InvocationError.invalidInvocation)
167277
}
168278

169-
public func send(nonce: EthereumQuantity? = nil, from: EthereumAddress, value: EthereumQuantity?, gas: EthereumQuantity, gasPrice: EthereumQuantity?, completion: @escaping (EthereumData?, Error?) -> Void) {
279+
public func send(
280+
nonce: EthereumQuantity? = nil,
281+
gasPrice: EthereumQuantity? = nil,
282+
maxFeePerGas: EthereumQuantity? = nil,
283+
maxPriorityFeePerGas: EthereumQuantity? = nil,
284+
gasLimit: EthereumQuantity? = nil,
285+
from: EthereumAddress,
286+
value: EthereumQuantity? = nil,
287+
accessList: OrderedDictionary<EthereumAddress, [EthereumData]> = [:],
288+
transactionType: EthereumTransaction.TransactionType = .legacy,
289+
completion: @escaping (EthereumData?, Error?) -> Void
290+
) {
170291
guard handler.address != nil else {
171292
completion(nil, InvocationError.contractNotDeployed)
172293
return
173294
}
174-
guard let transaction = createTransaction(nonce: nonce, from: from, value: value, gas: gas, gasPrice: gasPrice) else {
295+
guard let transaction = createTransaction(
296+
nonce: nonce,
297+
gasPrice: gasPrice,
298+
maxFeePerGas: maxFeePerGas,
299+
maxPriorityFeePerGas: maxPriorityFeePerGas,
300+
gasLimit: gasLimit,
301+
from: from,
302+
value: value,
303+
accessList: accessList,
304+
transactionType: transactionType
305+
) else {
175306
completion(nil, InvocationError.encodingError)
176307
return
177308
}
@@ -225,18 +356,62 @@ public struct SolidityConstructorInvocation {
225356
self.handler = handler
226357
self.payable = payable
227358
}
228-
229-
public func createTransaction(nonce: EthereumQuantity? = nil, from: EthereumAddress, value: EthereumQuantity = 0, gas: EthereumQuantity, gasPrice: EthereumQuantity?) -> EthereumTransaction? {
359+
360+
public func createTransaction(
361+
nonce: EthereumQuantity? = nil,
362+
gasPrice: EthereumQuantity? = nil,
363+
maxFeePerGas: EthereumQuantity? = nil,
364+
maxPriorityFeePerGas: EthereumQuantity? = nil,
365+
gasLimit: EthereumQuantity? = nil,
366+
from: EthereumAddress? = nil,
367+
value: EthereumQuantity? = nil,
368+
accessList: OrderedDictionary<EthereumAddress, [EthereumData]> = [:],
369+
transactionType: EthereumTransaction.TransactionType = .legacy
370+
) -> EthereumTransaction? {
230371
guard let data = encodeABI() else { return nil }
231-
return EthereumTransaction(nonce: nonce, gasPrice: gasPrice, gasLimit: gas, from: from, to: nil, value: value, data: data)
372+
373+
return EthereumTransaction(
374+
nonce: nonce,
375+
gasPrice: gasPrice,
376+
maxFeePerGas: maxFeePerGas,
377+
maxPriorityFeePerGas: maxPriorityFeePerGas,
378+
gasLimit: gasLimit,
379+
from: from,
380+
to: nil,
381+
value: value,
382+
data: data,
383+
accessList: accessList,
384+
transactionType: transactionType
385+
)
232386
}
233387

234-
public func send(nonce: EthereumQuantity? = nil, from: EthereumAddress, value: EthereumQuantity = 0, gas: EthereumQuantity, gasPrice: EthereumQuantity?, completion: @escaping (EthereumData?, Error?) -> Void) {
235-
guard payable == true || value == 0 else {
388+
public func send(
389+
nonce: EthereumQuantity? = nil,
390+
gasPrice: EthereumQuantity? = nil,
391+
maxFeePerGas: EthereumQuantity? = nil,
392+
maxPriorityFeePerGas: EthereumQuantity? = nil,
393+
gasLimit: EthereumQuantity? = nil,
394+
from: EthereumAddress,
395+
value: EthereumQuantity? = nil,
396+
accessList: OrderedDictionary<EthereumAddress, [EthereumData]> = [:],
397+
transactionType: EthereumTransaction.TransactionType = .legacy,
398+
completion: @escaping (EthereumData?, Error?) -> Void
399+
) {
400+
guard payable == true || value == nil || value == 0 else {
236401
completion(nil, InvocationError.invalidInvocation)
237402
return
238403
}
239-
guard let transaction = createTransaction(nonce: nonce, from: from, value: value, gas: gas, gasPrice: gasPrice) else {
404+
guard let transaction = createTransaction(
405+
nonce: nonce,
406+
gasPrice: gasPrice,
407+
maxFeePerGas: maxFeePerGas,
408+
maxPriorityFeePerGas: maxPriorityFeePerGas,
409+
gasLimit: gasLimit,
410+
from: from,
411+
value: value,
412+
accessList: accessList,
413+
transactionType: transactionType
414+
) else {
240415
completion(nil, InvocationError.encodingError)
241416
return
242417
}

Sources/Core/Web3/Web3.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,12 +305,12 @@ public struct Web3 {
305305
public func sendRawTransaction(
306306
transaction: EthereumSignedTransaction,
307307
response: @escaping Web3ResponseCompletion<EthereumData>
308-
) {
309-
let req = BasicRPCRequest(
308+
) throws {
309+
let req = try BasicRPCRequest(
310310
id: properties.rpcId,
311311
jsonrpc: Web3.jsonrpc,
312312
method: "eth_sendRawTransaction",
313-
params: [transaction.rlp()]
313+
params: [transaction.rawTransaction()]
314314
)
315315

316316
properties.provider.send(request: req, response: response)

0 commit comments

Comments
 (0)