Merge pull request #4326 from oa-s/#4325

[Refactor] Move token provider to wallet session #4325
pull/4330/head
Crypto Pank 3 years ago committed by GitHub
commit 50f6354123
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 20
      AlphaWallet/EtherClient/TrustClient/Models/RawTransaction.swift
  2. 26
      AlphaWallet/Transactions/EtherscanSingleChainTransactionProvider.swift
  3. 5
      AlphaWallet/Transactions/Storage/Session.swift
  4. 4
      AlphaWallet/Transactions/TokensFromTransactionsFetcher.swift

@ -53,7 +53,7 @@ struct RawTransaction: Decodable {
}
extension TransactionInstance {
static func from(transaction: RawTransaction, tokensDataStore: TokensDataStore, tokenProvider: TokenProviderType, server: RPCServer) -> Promise<TransactionInstance?> {
static func from(transaction: RawTransaction, tokensDataStore: TokensDataStore, session: WalletSession) -> Promise<TransactionInstance?> {
guard let from = AlphaWallet.Address(string: transaction.from) else {
return Promise.value(nil)
}
@ -68,11 +68,11 @@ extension TransactionInstance {
let to = AlphaWallet.Address(string: transaction.to)?.eip55String ?? transaction.to
return firstly {
createOperationForTokenTransfer(forTransaction: transaction, tokensDataStore: tokensDataStore, tokenProvider: tokenProvider, server: server)
createOperationForTokenTransfer(forTransaction: transaction, tokensDataStore: tokensDataStore, session: session)
}.then { operations -> Promise<TransactionInstance?> in
let result = TransactionInstance(
id: transaction.hash,
server: server,
server: session.server,
blockNumber: Int(transaction.blockNumber)!,
transactionIndex: Int(transaction.transactionIndex)!,
from: from.description,
@ -92,7 +92,7 @@ extension TransactionInstance {
}
}
static private func createOperationForTokenTransfer(forTransaction transaction: RawTransaction, tokensDataStore: TokensDataStore, tokenProvider: TokenProviderType, server: RPCServer) -> Promise<[LocalizedOperationObjectInstance]> {
static private func createOperationForTokenTransfer(forTransaction transaction: RawTransaction, tokensDataStore: TokensDataStore, session: WalletSession) -> Promise<[LocalizedOperationObjectInstance]> {
guard let contract = transaction.toAddress else {
return Promise.value([])
}
@ -103,10 +103,10 @@ extension TransactionInstance {
let result = LocalizedOperationObjectInstance(from: transaction.from, to: recipient.eip55String, contract: contract, type: operationType.rawValue, value: String(value), tokenId: "", symbol: token.symbol, name: token.name, decimals: token.decimals)
return .value([result])
} else {
let getContractName = tokenProvider.getContractName(for: contract)
let getContractSymbol = tokenProvider.getContractSymbol(for: contract)
let getDecimals = tokenProvider.getDecimals(for: contract)
let getTokenType = tokenProvider.getTokenType(for: contract)
let getContractName = session.tokenProvider.getContractName(for: contract)
let getContractSymbol = session.tokenProvider.getContractSymbol(for: contract)
let getDecimals = session.tokenProvider.getDecimals(for: contract)
let getTokenType = session.tokenProvider.getTokenType(for: contract)
return firstly {
when(fulfilled: getContractName, getContractSymbol, getDecimals, getTokenType)
@ -125,9 +125,9 @@ extension TransactionInstance {
if let functionCall = DecodedFunctionCall(data: data) {
switch functionCall.type {
case .erc20Transfer(let recipient, let value):
return generateLocalizedOperation(value: value, contract: contract, to: recipient, functionCall: functionCall, server: server)
return generateLocalizedOperation(value: value, contract: contract, to: recipient, functionCall: functionCall, server: session.server)
case .erc20Approve(let spender, let value):
return generateLocalizedOperation(value: value, contract: contract, to: spender, functionCall: functionCall, server: server)
return generateLocalizedOperation(value: value, contract: contract, to: spender, functionCall: functionCall, server: session.server)
case .nativeCryptoTransfer, .others:
break
case .erc1155SafeTransfer, .erc1155SafeBatchTransfer:

@ -25,8 +25,6 @@ class EtherscanSingleChainTransactionProvider: SingleChainTransactionProvider {
private var isAutoDetectingErc721Transactions: Bool = false
private var isFetchingLatestTransactions = false
private lazy var tokenProvider: TokenProviderType = TokenProvider(account: session.account, server: session.server)
required init(
session: WalletSession,
transactionDataStore: TransactionDataStore,
@ -44,7 +42,7 @@ class EtherscanSingleChainTransactionProvider: SingleChainTransactionProvider {
func start() {
runScheduledTimers()
if transactionsTracker.fetchingState != .done {
fetchOlderTransactions(for: session.account.address)
fetchOlderTransactions()
autoDetectERC20Transactions()
autoDetectErc721Transactions()
}
@ -92,7 +90,7 @@ class EtherscanSingleChainTransactionProvider: SingleChainTransactionProvider {
guard let strongSelf = self else { return .init(error: PMKError.cancelled) }
let (result, minBlockNumber, maxBlockNumber) = functional.extractBoundingBlockNumbers(fromTransactions: result)
return functional.backFillTransactionGroup(result, startBlock: minBlockNumber, endBlock: maxBlockNumber, session: strongSelf.session, alphaWalletProvider: strongSelf.alphaWalletProvider, tokensDataStore: strongSelf.tokensDataStore, tokenProvider: strongSelf.tokenProvider, queue: strongSelf.queue).map { ($0, maxBlockNumber) }
return functional.backFillTransactionGroup(result, startBlock: minBlockNumber, endBlock: maxBlockNumber, session: strongSelf.session, alphaWalletProvider: strongSelf.alphaWalletProvider, tokensDataStore: strongSelf.tokensDataStore, queue: strongSelf.queue).map { ($0, maxBlockNumber) }
}).done(on: queue, { [weak self] backFilledTransactions, maxBlockNumber in
guard let strongSelf = self else { return }
//Just to be sure, we don't want any kind of strange errors to clear our progress by resetting blockNumber = 0
@ -119,7 +117,7 @@ class EtherscanSingleChainTransactionProvider: SingleChainTransactionProvider {
}.then(on: queue, { [weak self] result -> Promise<([TransactionInstance], Int)> in
guard let strongSelf = self else { return .init(error: PMKError.cancelled) }
let (result, minBlockNumber, maxBlockNumber) = functional.extractBoundingBlockNumbers(fromTransactions: result)
return functional.backFillTransactionGroup(result, startBlock: minBlockNumber, endBlock: maxBlockNumber, session: strongSelf.session, alphaWalletProvider: strongSelf.alphaWalletProvider, tokensDataStore: strongSelf.tokensDataStore, tokenProvider: strongSelf.tokenProvider, queue: strongSelf.queue).map { ($0, maxBlockNumber) }
return functional.backFillTransactionGroup(result, startBlock: minBlockNumber, endBlock: maxBlockNumber, session: strongSelf.session, alphaWalletProvider: strongSelf.alphaWalletProvider, tokensDataStore: strongSelf.tokensDataStore, queue: strongSelf.queue).map { ($0, maxBlockNumber) }
}).done(on: queue, { [weak self] backFilledTransactions, maxBlockNumber in
guard let strongSelf = self else { return }
//Just to be sure, we don't want any kind of strange errors to clear our progress by resetting blockNumber = 0
@ -216,10 +214,10 @@ class EtherscanSingleChainTransactionProvider: SingleChainTransactionProvider {
fetchLatestTransactionsQueue.addOperation(operation)
}
private func fetchOlderTransactions(for address: AlphaWallet.Address) {
private func fetchOlderTransactions() {
guard let oldestCachedTransaction = transactionDataStore.lastTransaction(forServer: session.server, withTransactionState: .completed) else { return }
let promise = functional.fetchTransactions(for: address, startBlock: 1, endBlock: oldestCachedTransaction.blockNumber - 1, sortOrder: .desc, session: session, alphaWalletProvider: alphaWalletProvider, tokensDataStore: tokensDataStore, tokenProvider: tokenProvider, queue: queue)
let promise = functional.fetchTransactions(startBlock: 1, endBlock: oldestCachedTransaction.blockNumber - 1, sortOrder: .desc, session: session, alphaWalletProvider: alphaWalletProvider, tokensDataStore: tokensDataStore, queue: queue)
promise.done(on: queue, { [weak self] transactions in
guard let strongSelf = self else { return }
@ -230,7 +228,7 @@ class EtherscanSingleChainTransactionProvider: SingleChainTransactionProvider {
} else {
let timeout = DispatchTime.now() + .milliseconds(300)
DispatchQueue.main.asyncAfter(deadline: timeout) {
strongSelf.fetchOlderTransactions(for: address)
strongSelf.fetchOlderTransactions()
}
}
}).catch(on: queue, { [weak self] _ in
@ -283,7 +281,7 @@ class EtherscanSingleChainTransactionProvider: SingleChainTransactionProvider {
guard let coordinator = self.coordinator else { return }
firstly {
EtherscanSingleChainTransactionProvider.functional.fetchTransactions(for: session.account.address, startBlock: startBlock, sortOrder: sortOrder, session: coordinator.session, alphaWalletProvider: coordinator.alphaWalletProvider, tokensDataStore: coordinator.tokensDataStore, tokenProvider: coordinator.tokenProvider, queue: coordinator.queue)
EtherscanSingleChainTransactionProvider.functional.fetchTransactions(startBlock: startBlock, sortOrder: sortOrder, session: coordinator.session, alphaWalletProvider: coordinator.alphaWalletProvider, tokensDataStore: coordinator.tokensDataStore, queue: coordinator.queue)
}.done { transactions in
coordinator.addOrUpdate(transactions: transactions)
}.catch { e in
@ -317,8 +315,8 @@ extension EtherscanSingleChainTransactionProvider.functional {
}
}
static func fetchTransactions(for address: AlphaWallet.Address, startBlock: Int, endBlock: Int = 999_999_999, sortOrder: AlphaWalletService.SortOrder, session: WalletSession, alphaWalletProvider: MoyaProvider<AlphaWalletService>, tokensDataStore: TokensDataStore, tokenProvider: TokenProviderType, queue: DispatchQueue) -> Promise<[TransactionInstance]> {
let target: AlphaWalletService = .getTransactions(config: session.config, server: session.server, address: address, startBlock: startBlock, endBlock: endBlock, sortOrder: sortOrder)
static func fetchTransactions(startBlock: Int, endBlock: Int = 999_999_999, sortOrder: AlphaWalletService.SortOrder, session: WalletSession, alphaWalletProvider: MoyaProvider<AlphaWalletService>, tokensDataStore: TokensDataStore, queue: DispatchQueue) -> Promise<[TransactionInstance]> {
let target: AlphaWalletService = .getTransactions(config: session.config, server: session.server, address: session.account.address, startBlock: startBlock, endBlock: endBlock, sortOrder: sortOrder)
return firstly {
alphaWalletProvider.request(target)
}.then(on: queue) { response -> Promise<[TransactionInstance]> in
@ -330,7 +328,7 @@ extension EtherscanSingleChainTransactionProvider.functional {
throw E.statusCode404
}
let promises = try response.map(ArrayResponse<RawTransaction>.self).result.map {
TransactionInstance.from(transaction: $0, tokensDataStore: tokensDataStore, tokenProvider: tokenProvider, server: session.server)
TransactionInstance.from(transaction: $0, tokensDataStore: tokensDataStore, session: session)
}
return when(fulfilled: promises).compactMap(on: queue) {
@ -339,10 +337,10 @@ extension EtherscanSingleChainTransactionProvider.functional {
}
}
static func backFillTransactionGroup(_ transactionsToFill: [TransactionInstance], startBlock: Int, endBlock: Int, session: WalletSession, alphaWalletProvider: MoyaProvider<AlphaWalletService>, tokensDataStore: TokensDataStore, tokenProvider: TokenProviderType, queue: DispatchQueue) -> Promise<[TransactionInstance]> {
static func backFillTransactionGroup(_ transactionsToFill: [TransactionInstance], startBlock: Int, endBlock: Int, session: WalletSession, alphaWalletProvider: MoyaProvider<AlphaWalletService>, tokensDataStore: TokensDataStore, queue: DispatchQueue) -> Promise<[TransactionInstance]> {
guard !transactionsToFill.isEmpty else { return .value([]) }
return firstly {
fetchTransactions(for: session.account.address, startBlock: startBlock, endBlock: endBlock, sortOrder: .asc, session: session, alphaWalletProvider: alphaWalletProvider, tokensDataStore: tokensDataStore, tokenProvider: tokenProvider, queue: queue)
fetchTransactions(startBlock: startBlock, endBlock: endBlock, sortOrder: .asc, session: session, alphaWalletProvider: alphaWalletProvider, tokensDataStore: tokensDataStore, queue: queue)
}.map(on: queue) { fillerTransactions -> [TransactionInstance] in
var results: [TransactionInstance] = .init()
for each in transactionsToFill {

@ -8,17 +8,18 @@ class WalletSession {
let tokenBalanceService: TokenBalanceService
let config: Config
let chainState: ChainState
let tokenProvider: TokenProviderType
var sessionID: String {
return WalletSession.functional.sessionID(account: account, server: server)
}
init(account: Wallet, server: RPCServer, config: Config, tokenBalanceService: TokenBalanceService) {
self.account = account
self.server = server
self.config = config
self.chainState = ChainState(config: config, server: server)
self.tokenBalanceService = tokenBalanceService
self.tokenProvider = TokenProvider(account: account, server: server)
if config.development.isAutoFetchingDisabled {
//no-op

@ -15,7 +15,7 @@ protocol TokensFromTransactionsFetcherDelegate: AnyObject {
final class TokensFromTransactionsFetcher {
private let tokensDataStore: TokensDataStore
private let session: WalletSession
private lazy var tokenProvider: TokenProviderType = TokenProvider(account: session.account, server: session.server)
weak var delegate: TokensFromTransactionsFetcherDelegate?
init(tokensDataStore: TokensDataStore, session: WalletSession) {
@ -62,7 +62,7 @@ final class TokensFromTransactionsFetcher {
//The fetch ERC20 transactions endpoint from Etherscan returns only ERC20 token transactions but the Blockscout version also includes ERC721 transactions too (so it's likely other types that it can detect will be returned too); thus we check the token type rather than assume that they are all ERC20
let contracts = Array(Set(filteredTransactions.compactMap { $0.localizedOperations.first?.contractAddress }))
let tokenTypePromises = contracts.map { tokenProvider.getTokenType(for: $0) }
let tokenTypePromises = contracts.map { session.tokenProvider.getTokenType(for: $0) }
return when(fulfilled: tokenTypePromises)
.map { tokenTypes in

Loading…
Cancel
Save