@ -33,7 +33,7 @@ class EventSourceCoordinatorForActivities: EventSourceCoordinatorForActivitiesTy
let xmlHandler = XMLHandler ( contract : token . contractAddress , tokenType : token . type , assetDefinitionStore : assetDefinitionStore )
guard xmlHandler . hasAssetDefinition else { return [ ] }
return xmlHandler . activityCards . compactMap {
self . fetchEvents ( tokenContract : token . contractAddress , server : token . server , card : $0 )
EventSourceCoordinatorForActivities . functional . fetchEvents ( tokenContract : token . contractAddress , server : token . server , card : $0 , eventsDataStore : eventsDataStore , queue : queue , wallet : wallet )
}
}
@ -41,7 +41,7 @@ class EventSourceCoordinatorForActivities: EventSourceCoordinatorForActivitiesTy
let xmlHandler = XMLHandler ( contract : contract , tokenType : tokenType , assetDefinitionStore : assetDefinitionStore )
guard xmlHandler . hasAssetDefinition else { return [ ] }
return xmlHandler . activityCards . compactMap {
fetchEvents ( tokenContract : contract , server : rpcServer , card : $0 )
EventSourceCoordinatorForActivities . functional . fetchEvents ( tokenContract : contract , server : rpcServer , card : $0 , eventsDataStore : eventsDataStore , queue : queue , wallet : wallet )
}
}
@ -89,18 +89,24 @@ class EventSourceCoordinatorForActivities: EventSourceCoordinatorForActivitiesTy
seal . fulfill ( data )
}
}
}
}
private func fetchEvents ( tokenContract : AlphaWallet . Address , server : RPCServer , card : TokenScriptCard ) -> Promise < Void > ? {
extension EventSourceCoordinatorForActivities {
class functional { }
}
extension EventSourceCoordinatorForActivities . functional {
static func fetchEvents ( tokenContract : AlphaWallet . Address , server : RPCServer , card : TokenScriptCard , eventsDataStore : EventsActivityDataStoreProtocol , queue : DispatchQueue , wallet : Wallet ) -> Promise < Void > ? {
return Promise { seal in
self . queue . async {
queue . async {
let eventOrigin = card . eventOrigin
let ( filterName , filterValue ) = eventOrigin . eventFilter
let filterParam = eventOrigin . parameters . filter {
$0 . isIndexed
} . map {
self . formFilterFrom ( fromParameter : $0 , filterName : filterName , filterValue : filterValue )
EventSourceCoordinatorForActivities . functional . formFilterFrom ( fromParameter : $0 , filterName : filterName , filterValue : filterValue , wallet : wallet )
}
if filterParam . allSatisfy ( { $0 = = nil } ) {
@ -109,14 +115,14 @@ class EventSourceCoordinatorForActivities: EventSourceCoordinatorForActivitiesTy
return
}
self . eventsDataStore . getMatchingEventsSortedByBlockNumber ( forContract : eventOrigin . contract , tokenContract : tokenContract , server : server , eventName : eventOrigin . eventName ) . map ( on : self . queue , { oldEvent -> ( EventFilter . Block , UInt64 ) in
eventsDataStore . getMatchingEventsSortedByBlockNumber ( forContract : eventOrigin . contract , tokenContract : tokenContract , server : server , eventName : eventOrigin . eventName ) . map ( on : queue , { oldEvent -> ( EventFilter . Block , UInt64 ) in
if let newestEvent = oldEvent {
let value = UInt64 ( newestEvent . blockNumber + 1 )
return ( . blockNumber ( value ) , value )
} else {
return ( . blockNumber ( 0 ) , 0 )
}
} ) . map ( on : self . queue , { fromBlock -> EventFilter in
} ) . map ( on : queue , { fromBlock -> EventFilter in
let parameterFilters = filterParam . map { $0 ? . filter }
let addresses = [ EthereumAddress ( address : eventOrigin . contract ) ]
@ -128,9 +134,9 @@ class EventSourceCoordinatorForActivities: EventSourceCoordinatorForActivitiesTy
toBlock = . latest
}
return EventFilter ( fromBlock : fromBlock . 0 , toBlock : toBlock , addresses : addresses , parameterFilters : parameterFilters )
} ) . then ( on : self . queue , { eventFilter in
getEventLogs ( withServer : server , contract : eventOrigin . contract , eventName : eventOrigin . eventName , abiString : eventOrigin . eventAbiString , filter : eventFilter , queue : self . queue )
} ) . then ( on : self . queue , { events -> Promise < [ EventActivityInstance ] > in
} ) . then ( on : queue , { eventFilter in
getEventLogs ( withServer : server , contract : eventOrigin . contract , eventName : eventOrigin . eventName , abiString : eventOrigin . eventAbiString , filter : eventFilter , queue : queue )
} ) . then ( on : queue , { events -> Promise < [ EventActivityInstance ] > in
let promises = events . compactMap { event -> Promise < EventActivityInstance ? > in
guard let blockNumber = event . eventLog ? . blockNumber else {
return . value ( nil )
@ -138,21 +144,21 @@ class EventSourceCoordinatorForActivities: EventSourceCoordinatorForActivitiesTy
return GetBlockTimestampCoordinator ( )
. getBlockTimestamp ( blockNumber , onServer : server )
. map ( on : self . queue , { date in
. map ( on : queue , { date in
Self . convertEventToDatabaseObject ( event , date : date , filterParam : filterParam , eventOrigin : eventOrigin , tokenContract : tokenContract , server : server )
} ) . recover ( on : self . queue , { _ -> Promise < EventActivityInstance ? > in
} ) . recover ( on : queue , { _ -> Promise < EventActivityInstance ? > in
return . value ( nil )
} )
}
return when ( resolved : promises ) . map ( on : self . queue , { res -> [ EventActivityInstance ] in
return when ( resolved : promises ) . map ( on : queue , { res -> [ EventActivityInstance ] in
promises . compactMap { $0 . value } . compactMap { $0 }
} )
} ) . then ( on : self . queue , { events -> Promise < Void > in
} ) . then ( on : queue , { events -> Promise < Void > in
if events . isEmpty {
return . value ( ( ) )
} else {
return self . eventsDataStore . add ( events : events , forTokenContract : tokenContract ) . then ( on : self . queue , { _ -> Promise < Void > in
return eventsDataStore . add ( events : events , forTokenContract : tokenContract ) . then ( on : queue , { _ -> Promise < Void > in
return . value ( ( ) )
} )
}
@ -169,7 +175,7 @@ class EventSourceCoordinatorForActivities: EventSourceCoordinatorForActivitiesTy
guard let eventLog = event . eventLog else { return nil }
let transactionId = eventLog . transactionHash . hexEncoded
let decodedResult = Self . convertToJsonCompatible ( dictionary : event . decodedResult )
let decodedResult = EventSourceCoordinator . functional . convertToJsonCompatible ( dictionary : event . decodedResult )
guard let json = decodedResult . jsonString else { return nil }
// T O D O w h e n T o k e n S c r i p t s c h e m a a l l o w s i t , s u p p o r t m o r e t h a n 1 f i l t e r
let filterTextEquivalent = filterParam . compactMap ( { $0 ? . textEquivalent } ) . first
@ -178,30 +184,11 @@ class EventSourceCoordinatorForActivities: EventSourceCoordinatorForActivitiesTy
return EventActivityInstance ( contract : eventOrigin . contract , tokenContract : tokenContract , server : server , date : date , eventName : eventOrigin . eventName , blockNumber : Int ( eventLog . blockNumber ) , transactionId : transactionId , transactionIndex : Int ( eventLog . transactionIndex ) , logIndex : Int ( eventLog . logIndex ) , filter : filterText , json : json )
}
private static func convertToJsonCompatible ( dictionary : [ String : Any ] ) -> [ String : Any ] {
Dictionary ( uniqueKeysWithValues : dictionary . compactMap { key , value -> ( String , Any ) ? in
switch value {
case let address as EthereumAddress :
return ( key , address . address )
case let data as Data :
return ( key , data . hexEncoded )
case let string as String :
return ( key , string )
case let bigUInt as BigUInt :
// M u s t n o t d o ` I n t ( b i g U I n t ) ` b e c a u s e i t c r a s h e s u p o n o v e r f l o w
return ( key , String ( bigUInt ) )
default :
// W e o n l y a c c e p t k n o w n t y p e s , o t h e r w i s e s e r i a l i z i n g t o J S O N w i l l c r a s h
return nil
}
} )
}
private func formFilterFrom ( fromParameter parameter : EventParameter , filterName : String , filterValue : String ) -> ( filter : [ EventFilterable ] , textEquivalent : String ) ? {
private static func formFilterFrom ( fromParameter parameter : EventParameter , filterName : String , filterValue : String , wallet : Wallet ) -> ( filter : [ EventFilterable ] , textEquivalent : String ) ? {
guard parameter . name = = filterName else { return nil }
guard let parameterType = SolidityType ( rawValue : parameter . type ) else { return nil }
let optionalFilter : ( filter : AssetAttributeValueUsableAsFunctionArguments , textEquivalent : String ) ?
if let implicitAttribute = EventSourceCoordinatorForActivities . convertToImplicitAttribute ( string : filterValue ) {
if let implicitAttribute = EventSourceCoordinator . functional . convertToImplicitAttribute ( string : filterValue ) {
switch implicitAttribute {
case . tokenId :
optionalFilter = nil
@ -218,8 +205,4 @@ class EventSourceCoordinatorForActivities: EventSourceCoordinatorForActivitiesTy
guard let filterValueTypedForEventFilters = filterValue . coerceToArgumentTypeForEventFilter ( parameterType ) else { return nil }
return ( filter : [ filterValueTypedForEventFilters ] , textEquivalent : textEquivalent )
}
static func convertToImplicitAttribute ( string : String ) -> AssetImplicitAttributes ? {
EventSourceCoordinator . convertToImplicitAttribute ( string : string )
}
}