Skip to content

Commit d88a493

Browse files
committed
propagate async
1 parent 1008eef commit d88a493

8 files changed

+239
-260
lines changed

Sources/web3swift/Promises/Promise+Web3+Eth+GetTransactionCount.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ extension web3.Eth {
1717
public func getTransactionCountPromise(address: String, onBlock: String = "latest") async throws -> BigUInt {
1818
let request = JSONRPCRequestFabric.prepareRequest(.getTransactionCount, parameters: [address.lowercased(), onBlock])
1919
let response = try await web3.dispatch(request)
20-
let queue = web3.requestDispatcher.queue
2120

2221
guard let value: BigUInt = response.getValue() else {
2322
if response.error != nil {

Sources/web3swift/Promises/Promise+Web3+Eth+SendTransaction.swift

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,15 @@ extension web3.Eth {
1919
var forAssemblyPipeline: (EthereumTransaction, TransactionOptions) = (assembledTransaction, mergedOptions)
2020

2121
for hook in self.web3.preSubmissionHooks {
22-
let prom: Promise<Bool> = Promise<Bool> {seal in
23-
hook.queue.async {
24-
let hookResult = hook.function(forAssemblyPipeline)
25-
if hookResult.2 {
26-
forAssemblyPipeline = (hookResult.0, hookResult.1)
27-
}
28-
seal.fulfill(hookResult.2)
29-
}
22+
let hookResult = hook.function(forAssemblyPipeline)
23+
if hookResult.2 {
24+
forAssemblyPipeline = (hookResult.0, hookResult.1)
3025
}
31-
let shouldContinue = try prom.wait()
26+
27+
let shouldContinue = hookResult.2
3228
if !shouldContinue {
3329
throw Web3Error.processingError(desc: "Transaction is canceled by middleware")
3430
}
35-
3631
}
3732

3833
assembledTransaction = forAssemblyPipeline.0

Sources/web3swift/Promises/Promise+Web3+Personal+CreateAccount.swift

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,22 @@ import BigInt
99

1010

1111
extension web3.Personal {
12-
public func createAccountPromise(password: String = "web3swift") -> Promise<EthereumAddress> {
13-
let queue = web3.requestDispatcher.queue
14-
do {
15-
if self.web3.provider.attachedKeystoreManager == nil {
16-
let request = JSONRPCRequestFabric.prepareRequest(.createAccount, parameters: [password])
17-
return self.web3.dispatch(request).map(on: queue) {response in
18-
guard let value: EthereumAddress = response.getValue() else {
19-
if response.error != nil {
20-
throw Web3Error.nodeError(desc: response.error!.message)
21-
}
22-
throw Web3Error.nodeError(desc: "Invalid value from Ethereum node")
23-
}
24-
return value
25-
}
26-
}
12+
public func createAccountPromise(password: String = "web3swift") async throws -> EthereumAddress {
13+
14+
guard self.web3.provider.attachedKeystoreManager == nil else {
2715
throw Web3Error.inputError(desc: "Creating account in a local keystore with this method is not supported")
28-
} catch {
29-
let returnPromise = Promise<EthereumAddress>.pending()
30-
queue.async {
31-
returnPromise.resolver.reject(error)
16+
}
17+
18+
let request = JSONRPCRequestFabric.prepareRequest(.createAccount, parameters: [password])
19+
let response = try await self.web3.dispatch(request)
20+
21+
guard let value: EthereumAddress = response.getValue() else {
22+
if response.error != nil {
23+
throw Web3Error.nodeError(desc: response.error!.message)
3224
}
33-
return returnPromise.promise
25+
throw Web3Error.nodeError(desc: "Invalid value from Ethereum node")
3426
}
27+
return value
28+
3529
}
3630
}

Sources/web3swift/Utils/ENS/ENSReverseRegistrar.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,16 @@ public extension ENS {
5050
return transaction
5151
}
5252

53-
public func getReverseRecordName(address: EthereumAddress) throws -> Data {
53+
public func getReverseRecordName(address: EthereumAddress) async throws -> Data {
5454
guard let transaction = self.contract.read("node", parameters: [address] as [AnyObject], extraData: Data(), transactionOptions: defaultOptions) else {throw Web3Error.transactionSerializationError}
55-
guard let result = try? transaction.call(transactionOptions: defaultOptions) else {throw Web3Error.processingError(desc: "Can't call transaction")}
55+
guard let result = try? await transaction.call(transactionOptions: defaultOptions) else {throw Web3Error.processingError(desc: "Can't call transaction")}
5656
guard let name = result["0"] as? Data else {throw Web3Error.processingError(desc: "Can't get answer")}
5757
return name
5858
}
5959

60-
public func getDefaultResolver() throws -> EthereumAddress {
60+
public func getDefaultResolver() async throws -> EthereumAddress {
6161
guard let transaction = self.contract.read("defaultResolver", parameters: [] as [AnyObject], extraData: Data(), transactionOptions: defaultOptions) else {throw Web3Error.transactionSerializationError}
62-
guard let result = try? transaction.call(transactionOptions: defaultOptions) else {throw Web3Error.processingError(desc: "Can't call transaction")}
62+
guard let result = try? await transaction.call(transactionOptions: defaultOptions) else {throw Web3Error.processingError(desc: "Can't call transaction")}
6363
guard let address = result["0"] as? EthereumAddress else {throw Web3Error.processingError(desc: "Can't get answer")}
6464
return address
6565
}

Sources/web3swift/Utils/ENS/ETHRegistrarController.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,30 +29,30 @@ public extension ENS {
2929
self.address = address
3030
}
3131

32-
public func getRentPrice(name: String, duration: UInt) throws -> BigUInt {
32+
public func getRentPrice(name: String, duration: UInt) async throws -> BigUInt {
3333
guard let transaction = self.contract.read("rentPrice", parameters: [name, duration] as [AnyObject], extraData: Data(), transactionOptions: defaultOptions) else {throw Web3Error.transactionSerializationError}
34-
guard let result = try? transaction.call(transactionOptions: defaultOptions) else {throw Web3Error.processingError(desc: "Can't call transaction")}
34+
guard let result = try? await transaction.call(transactionOptions: defaultOptions) else {throw Web3Error.processingError(desc: "Can't call transaction")}
3535
guard let price = result["0"] as? BigUInt else {throw Web3Error.processingError(desc: "Can't get answer")}
3636
return price
3737
}
3838

39-
public func checkNameValidity(name: String) throws -> Bool {
39+
public func checkNameValidity(name: String) async throws -> Bool {
4040
guard let transaction = self.contract.read("valid", parameters: [name] as [AnyObject], extraData: Data(), transactionOptions: defaultOptions) else {throw Web3Error.transactionSerializationError}
41-
guard let result = try? transaction.call(transactionOptions: defaultOptions) else {throw Web3Error.processingError(desc: "Can't call transaction")}
41+
guard let result = try? await transaction.call(transactionOptions: defaultOptions) else {throw Web3Error.processingError(desc: "Can't call transaction")}
4242
guard let valid = result["0"] as? Bool else {throw Web3Error.processingError(desc: "Can't get answer")}
4343
return valid
4444
}
4545

46-
public func isNameAvailable(name: String) throws -> Bool {
46+
public func isNameAvailable(name: String) async throws -> Bool {
4747
guard let transaction = self.contract.read("available", parameters: [name as AnyObject], extraData: Data(), transactionOptions: defaultOptions) else {throw Web3Error.transactionSerializationError}
48-
guard let result = try? transaction.call(transactionOptions: defaultOptions) else {throw Web3Error.processingError(desc: "Can't call transaction")}
48+
guard let result = try? await transaction.call(transactionOptions: defaultOptions) else {throw Web3Error.processingError(desc: "Can't call transaction")}
4949
guard let available = result["0"] as? Bool else {throw Web3Error.processingError(desc: "Can't get answer")}
5050
return available
5151
}
5252

53-
public func calculateCommitmentHash(name: String, owner: EthereumAddress, secret: String) throws -> Data {
53+
public func calculateCommitmentHash(name: String, owner: EthereumAddress, secret: String) async throws -> Data {
5454
guard let transaction = self.contract.read("makeCommitment", parameters: [name, owner.address, secret] as [AnyObject], extraData: Data(), transactionOptions: defaultOptions) else {throw Web3Error.transactionSerializationError}
55-
guard let result = try? transaction.call(transactionOptions: defaultOptions) else {throw Web3Error.processingError(desc: "Can't call transaction")}
55+
guard let result = try? await transaction.call(transactionOptions: defaultOptions) else {throw Web3Error.processingError(desc: "Can't call transaction")}
5656
guard let hash = result["0"] as? Data else {throw Web3Error.processingError(desc: "Can't get answer")}
5757
return hash
5858
}

Sources/web3swift/Web3/Web3+EventParser.swift

Lines changed: 69 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -87,23 +87,23 @@ extension web3.web3contract {
8787
- important: This call is synchronous
8888

8989
*/
90-
public func parseTransaction(_ transaction: EthereumTransaction) throws -> [EventParserResultProtocol] {
91-
let result = try self.parseTransactionPromise(transaction)
90+
public func parseTransaction(_ transaction: EthereumTransaction) async throws -> [EventParserResultProtocol] {
91+
let result = try await self.parseTransactionPromise(transaction)
9292
return result
9393
}
9494
}
9595
}
9696

9797
extension web3.web3contract.EventParser {
98-
public func parseTransactionPromise(_ transaction: EthereumTransaction) throws -> [EventParserResultProtocol] {
98+
public func parseTransactionPromise(_ transaction: EthereumTransaction) async throws -> [EventParserResultProtocol] {
9999
guard let hash = transaction.hash else {
100100
throw Web3Error.processingError(desc: "Failed to get transaction hash")
101101
}
102-
return try self.parseTransactionByHashPromise(hash)
102+
return try await self.parseTransactionByHashPromise(hash)
103103
}
104104

105-
public func parseTransactionByHashPromise(_ hash: Data) throws -> [EventParserResultProtocol] {
106-
let receipt = self.web3.eth.getTransactionReceiptPromise(hash)
105+
public func parseTransactionByHashPromise(_ hash: Data) async throws -> [EventParserResultProtocol] {
106+
let receipt = try await self.web3.eth.getTransactionReceiptPromise(hash)
107107

108108
guard let results = parseReceiptForLogs(receipt: receipt, contract: contract, eventName: eventName, filter: filter) else {
109109
throw Web3Error.processingError(desc: "Failed to parse receipt for events")
@@ -143,42 +143,40 @@ extension web3.web3contract.EventParser {
143143
}
144144

145145

146-
return Promise {seal in
147-
148-
var pendingEvents: [Promise<[EventParserResultProtocol]>] = [Promise<[EventParserResultProtocol]>]()
149-
for transaction in block.transactions {
150-
switch transaction {
151-
case .null:
152-
seal.reject(Web3Error.processingError(desc: "No information about transactions in block"))
153-
return
154-
case .transaction(let tx):
155-
guard let hash = tx.hash else {
156-
seal.reject(Web3Error.processingError(desc: "Failed to get transaction hash"))
157-
return
158-
}
159-
let subresultPromise = self.parseTransactionByHashPromise(hash)
160-
pendingEvents.append(subresultPromise)
161-
case .hash(let hash):
162-
let subresultPromise = self.parseTransactionByHashPromise(hash)
163-
pendingEvents.append(subresultPromise)
146+
147+
148+
var pendingEvents: [[EventParserResultProtocol]] = [[EventParserResultProtocol]]()
149+
for transaction in block.transactions {
150+
switch transaction {
151+
case .null:
152+
throw Web3Error.processingError(desc: "No information about transactions in block")
153+
case .transaction(let tx):
154+
guard let hash = tx.hash else {
155+
throw Web3Error.processingError(desc: "Failed to get transaction hash")
164156
}
157+
let subresultPromise = try self.parseTransactionByHashPromise(hash)
158+
pendingEvents.append(subresultPromise)
159+
case .hash(let hash):
160+
let subresultPromise = try self.parseTransactionByHashPromise(hash)
161+
pendingEvents.append(subresultPromise)
165162
}
163+
}
166164

167-
when(resolved: pendingEvents).done(on: queue){ (results: [PromiseResult<[EventParserResultProtocol]>]) throws in
168-
var allResults = [EventParserResultProtocol]()
169-
for res in results {
170-
guard case .fulfilled(let subresult) = res else {
171-
throw Web3Error.processingError(desc: "Failed to parse event for one transaction in block")
172-
}
173-
allResults.append(contentsOf: subresult)
165+
when(resolved: pendingEvents).done(on: queue){ (results: [PromiseResult<[EventParserResultProtocol]>]) throws in
166+
var allResults = [EventParserResultProtocol]()
167+
for res in results {
168+
guard case .fulfilled(let subresult) = res else {
169+
throw Web3Error.processingError(desc: "Failed to parse event for one transaction in block")
174170
}
175-
seal.fulfill(allResults)
176-
}
177-
.catch(on: queue) {err in
178-
seal.reject(err)
171+
allResults.append(contentsOf: subresult)
179172
}
173+
seal.fulfill(allResults)
174+
}
175+
.catch(on: queue) {err in
176+
seal.reject(err)
180177
}
181178

179+
182180
}
183181

184182
}
@@ -206,9 +204,8 @@ extension web3.web3contract {
206204
}
207205

208206
extension web3.web3contract {
209-
public func getIndexedEventsPromise(eventName: String?, filter: EventFilter, joinWithReceipts: Bool = false) -> Promise<[EventParserResultProtocol]> {
210-
let queue = self.web3.requestDispatcher.queue
211-
do {
207+
public func getIndexedEventsPromise(eventName: String?, filter: EventFilter, joinWithReceipts: Bool = false) async throws -> [EventParserResultProtocol] {
208+
212209
let rawContract = self.contract
213210
guard let preEncoding = encodeTopicToGetLogs(contract: rawContract, eventName: eventName, filter: filter) else {
214211
throw Web3Error.processingError(desc: "Failed to encode topic for request")
@@ -220,52 +217,50 @@ extension web3.web3contract {
220217
}
221218
}
222219
let request = JSONRPCRequestFabric.prepareRequest(.getLogs, parameters: [preEncoding])
223-
let fetchLogsPromise = self.web3.dispatch(request).map(on: queue) {response throws -> [EventParserResult] in
224-
guard let value: [EventLog] = response.getValue() else {
225-
if response.error != nil {
226-
throw Web3Error.nodeError(desc: response.error!.message)
227-
}
228-
throw Web3Error.nodeError(desc: "Empty or malformed response")
229-
}
230-
let allLogs = value
231-
let decodedLogs = allLogs.compactMap({ (log) -> EventParserResult? in
232-
let (n, d) = self.contract.parseEvent(log)
233-
guard let evName = n, let evData = d else {return nil}
234-
var res = EventParserResult(eventName: evName, transactionReceipt: nil, contractAddress: log.address, decodedResult: evData)
235-
res.eventLog = log
236-
return res
237-
}).filter{ (res: EventParserResult?) -> Bool in
238-
if eventName != nil {
239-
if res != nil && res?.eventName == eventName && res!.eventLog != nil {
240-
return true
241-
}
242-
} else {
243-
if res != nil && res!.eventLog != nil {
244-
return true
245-
}
246-
}
247-
return false
220+
let response = try await self.web3.dispatch(request)
221+
222+
guard let allLogs: [EventLog] = response.getValue() else {
223+
if response.error != nil {
224+
throw Web3Error.nodeError(desc: response.error!.message)
248225
}
249-
return decodedLogs
226+
throw Web3Error.nodeError(desc: "Empty or malformed response")
227+
}
228+
229+
230+
let decodedLogs = allLogs.compactMap { (log) -> EventParserResult? in
231+
let (n, d) = self.contract.parseEvent(log)
232+
guard let evName = n, let evData = d else {return nil}
233+
var res = EventParserResult(eventName: evName, transactionReceipt: nil, contractAddress: log.address, decodedResult: evData)
234+
res.eventLog = log
235+
return res
250236
}
237+
.filter{ res in res.eventLog != nil || (res.eventName == eventName && eventName != nil)}
238+
239+
251240
if (!joinWithReceipts) {
252-
return fetchLogsPromise.mapValues(on: queue) {res -> EventParserResultProtocol in
253-
return res as EventParserResultProtocol
254-
}
241+
return decodedLogs as [EventParserResultProtocol]
255242
}
256-
return fetchLogsPromise.thenMap(on: queue) {singleEvent in
257-
return self.web3.eth.getTransactionReceiptPromise(singleEvent.eventLog!.transactionHash).map(on: queue) { receipt in
243+
244+
245+
return await withTaskGroup(of: EventParserResultProtocol.self, returning: [EventParserResultProtocol].self) { group -> [EventParserResultProtocol] in
246+
247+
decodedLogs.forEach { singleEvent in
248+
group.addTask {
258249
var joinedEvent = singleEvent
250+
let receipt = try? await self.web3.eth.getTransactionReceiptPromise(singleEvent.eventLog!.transactionHash)
259251
joinedEvent.transactionReceipt = receipt
260252
return joinedEvent as EventParserResultProtocol
261253
}
262254
}
263-
} catch {
264-
let returnPromise = Promise<[EventParserResultProtocol]>.pending()
265-
queue.async {
266-
returnPromise.resolver.reject(error)
255+
256+
var collected = [EventParserResultProtocol]()
257+
258+
for await value in group {
259+
collected.append(value)
267260
}
268-
return returnPromise.promise
261+
262+
return collected
263+
269264
}
270265
}
271266
}

Sources/web3swift/Web3/Web3+InfuraProviders.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ public enum BlockNumber {
2929

3030
/// Custom Web3 HTTP provider of Infura nodes.
3131
public final class InfuraProvider: Web3HttpProvider {
32-
public init?(_ net: Networks, accessToken token: String? = nil, keystoreManager manager: KeystoreManager? = nil) {
32+
public init?(_ net: Networks, accessToken token: String? = nil, keystoreManager manager: KeystoreManager? = nil) async {
3333
var requestURLstring = "https://" + net.name + Constants.infuraHttpScheme
3434
requestURLstring += token ?? Constants.infuraToken
3535
let providerURL = URL(string: requestURLstring)
36-
super.init(providerURL!, network: net, keystoreManager: manager)
36+
await super.init(providerURL!, network: net, keystoreManager: manager)
3737
}
3838
}
3939

0 commit comments

Comments
 (0)