Skip to content

Commit 70e95d0

Browse files
author
Alex Vlasov
committed
fix some json deserializations. All main operations are now promisified
1 parent 90c9eff commit 70e95d0

11 files changed

+247
-77
lines changed

web3swift.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
8116666420455E33008D8AD0 /* Web3+Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81C0FCEF20440C3600D82FAF /* Web3+Wallet.swift */; };
8282
81166665204565AC008D8AD0 /* Web3+BrowserFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81C0FCF8204456E600D82FAF /* Web3+BrowserFunctions.swift */; };
8383
81166666204565AD008D8AD0 /* Web3+BrowserFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81C0FCF8204456E600D82FAF /* Web3+BrowserFunctions.swift */; };
84+
81195AB020D7FF8500ABC6B1 /* Promise+Web3+Contract+GetIndexedEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81195AAF20D7FF8500ABC6B1 /* Promise+Web3+Contract+GetIndexedEvents.swift */; };
8485
8123E1C7200CBAC200B6D3AB /* Dictionary+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8123E1C6200CBAC200B6D3AB /* Dictionary+Extension.swift */; };
8586
8123E1C9200CBAF800B6D3AB /* Data+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8123E1C8200CBAF800B6D3AB /* Data+Extension.swift */; };
8687
8123E1CB200CBB2200B6D3AB /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8123E1CA200CBB2200B6D3AB /* Array+Extension.swift */; };
@@ -271,6 +272,7 @@
271272
8113D3191FD7F4C80074282C /* ABITypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ABITypes.swift; sourceTree = "<group>"; };
272273
8113D31B1FD7F8980074282C /* ABIRecordParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ABIRecordParser.swift; sourceTree = "<group>"; };
273274
8113DE7B1FD8514400CD8DF1 /* NSRegularExpressionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSRegularExpressionExtension.swift; sourceTree = "<group>"; };
275+
81195AAF20D7FF8500ABC6B1 /* Promise+Web3+Contract+GetIndexedEvents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Promise+Web3+Contract+GetIndexedEvents.swift"; sourceTree = "<group>"; };
274276
8123E1C6200CBAC200B6D3AB /* Dictionary+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+Extension.swift"; sourceTree = "<group>"; };
275277
8123E1C8200CBAF800B6D3AB /* Data+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Extension.swift"; sourceTree = "<group>"; };
276278
8123E1CA200CBB2200B6D3AB /* Array+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extension.swift"; sourceTree = "<group>"; };
@@ -641,6 +643,7 @@
641643
81A1824420D7B91B0016741F /* Promise+Web3+Intermediate+Send.swift */,
642644
81A1824720D7DDA20016741F /* Promise+Web3+Personal+Sign.swift */,
643645
81A1824A20D7DF1B0016741F /* Promise+Web3+Personal+UnlockAccount.swift */,
646+
81195AAF20D7FF8500ABC6B1 /* Promise+Web3+Contract+GetIndexedEvents.swift */,
644647
);
645648
path = Classes;
646649
sourceTree = "<group>";
@@ -1053,6 +1056,7 @@
10531056
8125F06920499AC300A0F2FE /* BloomFilter.swift in Sources */,
10541057
818ABD591FE95558002657BB /* Web3+Infura.swift in Sources */,
10551058
810B0F9A1FEC446B00CF0DA2 /* Web3+JSONRPC.swift in Sources */,
1059+
81195AB020D7FF8500ABC6B1 /* Promise+Web3+Contract+GetIndexedEvents.swift in Sources */,
10561060
8125F0662047D9FF00A0F2FE /* ABIEncoder.swift in Sources */,
10571061
8113D2C61FD7E1590074282C /* LibSecp256k1Extension.swift in Sources */,
10581062
81EB1E4B208173D7003BD47F /* Web3+Personal.swift in Sources */,

web3swift/Promises/Classes/Promise+HttpProvider.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ extension Web3HttpProvider {
4646
task = nil
4747
}.map(on: queue){ (data: Data) throws -> JSONRPCresponse in
4848
let parsedResponse = try JSONDecoder().decode(JSONRPCresponse.self, from: data)
49+
if parsedResponse.error != nil {
50+
throw Web3Error.nodeError("Received an error message from node\n" + String(describing: parsedResponse.error!))
51+
}
4952
return parsedResponse
5053
}
5154
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//
2+
// Promise+Web3+Contract+GetIndexedEvents.swift
3+
// web3swift-iOS
4+
//
5+
// Created by Alexander Vlasov on 18.06.2018.
6+
// Copyright © 2018 Bankex Foundation. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import PromiseKit
11+
12+
extension web3.web3contract {
13+
public func getIndexedEventsPromise(eventName: String?, filter: EventFilter, joinWithReceipts: Bool = false) -> Promise<[EventParserResultProtocol]> {
14+
let queue = self.web3.requestDispatcher.queue
15+
do {
16+
guard let rawContract = self.contract as? ContractV2 else {
17+
throw Web3Error.nodeError("ABIv1 is not supported for this method")
18+
}
19+
guard let preEncoding = encodeTopicToGetLogs(contract: rawContract, eventName: eventName, filter: filter) else {
20+
throw Web3Error.processingError("Failed to encode topic for request")
21+
}
22+
// var event: ABIv2.Element.Event? = nil
23+
if eventName != nil {
24+
guard let _ = rawContract.events[eventName!] else {
25+
throw Web3Error.processingError("No such event in a contract")
26+
}
27+
// event = ev
28+
}
29+
let request = JSONRPCRequestFabric.prepareRequest(.getLogs, parameters: [preEncoding])
30+
let fetchLogsPromise = self.web3.dispatch(request).map(on: queue) {response throws -> [EventParserResult] in
31+
guard let value: [EventLog] = response.getValue() else {
32+
throw Web3Error.nodeError("Empty or malformed response")
33+
}
34+
let allLogs = value
35+
let decodedLogs = allLogs.compactMap({ (log) -> EventParserResult? in
36+
let (n, d) = self.contract.parseEvent(log)
37+
guard let evName = n, let evData = d else {return nil}
38+
var res = EventParserResult(eventName: evName, transactionReceipt: nil, contractAddress: log.address, decodedResult: evData)
39+
res.eventLog = log
40+
return res
41+
}).filter{ (res:EventParserResult?) -> Bool in
42+
if eventName != nil {
43+
if res != nil && res?.eventName == eventName && res!.eventLog != nil {
44+
return true
45+
}
46+
} else {
47+
if res != nil && res!.eventLog != nil {
48+
return true
49+
}
50+
}
51+
return false
52+
}
53+
return decodedLogs
54+
}
55+
if (!joinWithReceipts) {
56+
return fetchLogsPromise.mapValues(on: queue) {res -> EventParserResultProtocol in
57+
return res as EventParserResultProtocol
58+
}
59+
}
60+
return fetchLogsPromise.thenMap(on:queue) {singleEvent in
61+
return self.web3.eth.getTransactionReceiptPromise(singleEvent.eventLog!.transactionHash).map(on: queue) { receipt in
62+
var joinedEvent = singleEvent
63+
joinedEvent.transactionReceipt = receipt
64+
return joinedEvent as EventParserResultProtocol
65+
}
66+
}
67+
} catch {
68+
let returnPromise = Promise<[EventParserResultProtocol]>.pending()
69+
queue.async {
70+
returnPromise.resolver.reject(error)
71+
}
72+
return returnPromise.promise
73+
}
74+
}
75+
}

web3swift/Promises/Classes/Promise+Web3+Eth+GetBlockByHash.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ extension web3.Eth {
1717
}
1818

1919
public func getBlockByHashPromise(_ hash: String, fullTransactions: Bool = false) -> Promise<Block> {
20-
let request = JSONRPCRequestFabric.prepareRequest(.getBlockByHash, parameters: [hash])
20+
let request = JSONRPCRequestFabric.prepareRequest(.getBlockByHash, parameters: [hash, fullTransactions])
2121
let rp = web3.dispatch(request)
2222
let queue = web3.requestDispatcher.queue
2323
return rp.map(on: queue ) { response in

web3swift/Promises/Classes/Promise+Web3+Eth+GetBlockByNumber.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extension web3.Eth {
2222
}
2323

2424
public func getBlockByNumberPromise(_ number: String, fullTransactions: Bool = false) -> Promise<Block> {
25-
let request = JSONRPCRequestFabric.prepareRequest(.getBlockByNumber, parameters: [number])
25+
let request = JSONRPCRequestFabric.prepareRequest(.getBlockByNumber, parameters: [number, fullTransactions])
2626
let rp = web3.dispatch(request)
2727
let queue = web3.requestDispatcher.queue
2828
return rp.map(on: queue ) { response in

web3swift/Web3/Classes/Web3+EventParser.swift

Lines changed: 123 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,128 @@ extension web3.web3contract {
100100
}
101101
}
102102

103+
extension web3.web3contract.EventParser {
104+
public func parseTransactionPromise(_ transaction: EthereumTransaction) -> Promise<[EventParserResultProtocol]> {
105+
let queue = self.web3.requestDispatcher.queue
106+
do {
107+
guard let hash = transaction.hash else {
108+
throw Web3Error.processingError("Failed to get transaction hash")}
109+
return self.parseTransactionByHashPromise(hash)
110+
} catch {
111+
let returnPromise = Promise<[EventParserResultProtocol]>.pending()
112+
queue.async {
113+
returnPromise.resolver.reject(error)
114+
}
115+
return returnPromise.promise
116+
}
117+
}
118+
119+
public func parseTransactionByHashPromise(_ hash: Data) -> Promise<[EventParserResultProtocol]> {
120+
let queue = self.web3.requestDispatcher.queue
121+
return self.web3.eth.getTransactionReceiptPromise(hash).map(on:queue) {receipt throws -> [EventParserResultProtocol] in
122+
guard let results = parseReceiptForLogs(receipt: receipt, contract: self.contract, eventName: self.eventName, filter: self.filter) else {
123+
throw Web3Error.processingError("Failed to parse receipt for events")
124+
}
125+
return results
126+
}
127+
}
128+
129+
public func parseBlockByNumberPromise(_ blockNumber: UInt64) -> Promise<[EventParserResultProtocol]> {
130+
let queue = self.web3.requestDispatcher.queue
131+
do {
132+
if self.filter != nil && (self.filter?.fromBlock != nil || self.filter?.toBlock != nil) {
133+
throw Web3Error.inputError("Can not mix parsing specific block and using block range filter")
134+
}
135+
return self.web3.eth.getBlockByNumberPromise(blockNumber).then(on: queue) {res in
136+
return self.parseBlockPromise(res)
137+
}
138+
} catch {
139+
let returnPromise = Promise<[EventParserResultProtocol]>.pending()
140+
queue.async {
141+
returnPromise.resolver.reject(error)
142+
}
143+
return returnPromise.promise
144+
}
145+
}
146+
147+
public func parseBlockPromise(_ block: Block) -> Promise<[EventParserResultProtocol]> {
148+
let queue = self.web3.requestDispatcher.queue
149+
do {
150+
guard let bloom = block.logsBloom else {
151+
throw Web3Error.processingError("Block doesn't have a bloom filter log")
152+
}
153+
if self.contract.address != nil {
154+
let addressPresent = block.logsBloom?.test(topic: self.contract.address!.addressData)
155+
if (addressPresent != true) {
156+
let returnPromise = Promise<[EventParserResultProtocol]>.pending()
157+
queue.async {
158+
returnPromise.resolver.fulfill([EventParserResultProtocol]())
159+
}
160+
return returnPromise.promise
161+
}
162+
}
163+
guard let eventOfSuchTypeIsPresent = self.contract.testBloomForEventPrecence(eventName: self.eventName, bloom: bloom) else {
164+
throw Web3Error.processingError("Error processing bloom for events")
165+
}
166+
if (!eventOfSuchTypeIsPresent) {
167+
let returnPromise = Promise<[EventParserResultProtocol]>.pending()
168+
queue.async {
169+
returnPromise.resolver.fulfill([EventParserResultProtocol]())
170+
}
171+
return returnPromise.promise
172+
}
173+
return Promise {seal in
174+
175+
var pendingEvents : [Promise<[EventParserResultProtocol]>] = [Promise<[EventParserResultProtocol]>]()
176+
for transaction in block.transactions {
177+
switch transaction {
178+
case .null:
179+
seal.reject(Web3Error.processingError("No information about transactions in block"))
180+
return
181+
case .transaction(let tx):
182+
guard let hash = tx.hash else {
183+
seal.reject(Web3Error.processingError("Failed to get transaction hash"))
184+
return
185+
}
186+
let subresultPromise = self.parseTransactionByHashPromise(hash)
187+
pendingEvents.append(subresultPromise)
188+
case .hash(let hash):
189+
let subresultPromise = self.parseTransactionByHashPromise(hash)
190+
pendingEvents.append(subresultPromise)
191+
}
192+
}
193+
when(resolved: pendingEvents).done(on: queue){ (results:[PromiseResult<[EventParserResultProtocol]>]) throws in
194+
var allResults = [EventParserResultProtocol]()
195+
for res in results {
196+
guard case .fulfilled(let subresult) = res else {
197+
throw Web3Error.processingError("Failed to parse event for one transaction in block")
198+
}
199+
allResults.append(contentsOf: subresult)
200+
}
201+
seal.fulfill(allResults)
202+
}.catch(on:queue) {err in
203+
seal.reject(err)
204+
}
205+
}
206+
} catch {
207+
// let returnPromise = Promise<[EventParserResultProtocol]>.pending()
208+
// queue.async {
209+
// returnPromise.resolver.fulfill([EventParserResultProtocol]())
210+
// }
211+
// return returnPromise.promise
212+
let returnPromise = Promise<[EventParserResultProtocol]>.pending()
213+
queue.async {
214+
returnPromise.resolver.reject(error)
215+
}
216+
return returnPromise.promise
217+
}
218+
}
219+
220+
}
221+
222+
223+
224+
103225
extension web3.web3contract {
104226
public func getIndexedEvents(eventName: String?, filter: EventFilter) -> Result<[EventParserResultProtocol], Web3Error> {
105227
guard let rawContract = self.contract as? ContractV2 else {return Result.failure(Web3Error.nodeError("ABIv1 is not supported for this method"))}
@@ -150,69 +272,6 @@ extension web3.web3contract {
150272
}
151273
}
152274

153-
extension web3.web3contract {
154-
public func getIndexedEventsPromise(eventName: String?, filter: EventFilter, joinWithReceipts: Bool = false) -> Promise<[EventParserResultProtocol]> {
155-
let queue = self.web3.requestDispatcher.queue
156-
do {
157-
guard let rawContract = self.contract as? ContractV2 else {
158-
throw Web3Error.nodeError("ABIv1 is not supported for this method")
159-
}
160-
guard let preEncoding = encodeTopicToGetLogs(contract: rawContract, eventName: eventName, filter: filter) else {
161-
throw Web3Error.processingError("Failed to encode topic for request")
162-
}
163-
// var event: ABIv2.Element.Event? = nil
164-
if eventName != nil {
165-
guard let _ = rawContract.events[eventName!] else {
166-
throw Web3Error.processingError("No such event in a contract")
167-
}
168-
// event = ev
169-
}
170-
let request = JSONRPCRequestFabric.prepareRequest(.getLogs, parameters: [preEncoding])
171-
let fetchLogsPromise = self.web3.dispatch(request).map(on: queue) {response throws -> [EventParserResult] in
172-
guard let value: [EventLog] = response.getValue() else {
173-
throw Web3Error.nodeError("Empty or malformed response")
174-
}
175-
let allLogs = value
176-
let decodedLogs = allLogs.compactMap({ (log) -> EventParserResult? in
177-
let (n, d) = self.contract.parseEvent(log)
178-
guard let evName = n, let evData = d else {return nil}
179-
var res = EventParserResult(eventName: evName, transactionReceipt: nil, contractAddress: log.address, decodedResult: evData)
180-
res.transactionHash = log.transactionHash
181-
return res
182-
}).filter{ (res:EventParserResult?) -> Bool in
183-
if eventName != nil {
184-
if res != nil && res?.eventName == eventName && res?.transactionHash != nil {
185-
return true
186-
}
187-
} else {
188-
if res != nil && res?.transactionHash != nil {
189-
return true
190-
}
191-
}
192-
return false
193-
}
194-
return decodedLogs
195-
}
196-
if (!joinWithReceipts) {
197-
return fetchLogsPromise.mapValues(on: queue) {res -> EventParserResultProtocol in
198-
return res as EventParserResultProtocol
199-
}
200-
}
201-
return fetchLogsPromise.thenMap(on:queue) {singleEvent in
202-
return self.web3.eth.getTransactionReceiptPromise(singleEvent.transactionHash!).map(on: queue) { receipt in
203-
var joinedEvent = singleEvent
204-
joinedEvent.transactionReceipt = receipt
205-
return joinedEvent as EventParserResultProtocol
206-
}
207-
}
208-
} catch {
209-
let returnPromise = Promise<[EventParserResultProtocol]>.pending()
210-
queue.async {
211-
returnPromise.resolver.reject(error)
212-
}
213-
return returnPromise.promise
214-
}
215-
}
216-
}
275+
217276

218277

0 commit comments

Comments
 (0)