-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IOS-8316 [Casper] Make blockchain implementation #4141
base: blockchains/casper/IOS-8332_make_casper_address_service
Are you sure you want to change the base?
Changes from 16 commits
573bfab
44b66b7
b4484da
f669a4b
9d28bd7
0ba1c6e
6c5bd35
ff058fd
63c81c8
da89400
60369ee
f643792
dcfcd27
f9cd1f7
c9600ec
4afdfbd
051842c
2f4785e
a6aa213
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,16 +11,43 @@ import Combine | |
|
||
class CasperWalletManager: BaseManager, WalletManager { | ||
var currentHost: String { | ||
// TODO: - https://tangem.atlassian.net/browse/IOS-8316 | ||
"" | ||
networkService.host | ||
} | ||
|
||
var allowsFeeSelection: Bool { | ||
false | ||
} | ||
|
||
// MARK: - Private Implementation | ||
|
||
private let networkService: CasperNetworkService | ||
|
||
// MARK: - Init | ||
|
||
init(wallet: Wallet, networkService: CasperNetworkService) { | ||
self.networkService = networkService | ||
super.init(wallet: wallet) | ||
} | ||
|
||
// MARK: - Manager Implementation | ||
|
||
override func update(completion: @escaping (Result<Void, any Error>) -> Void) { | ||
// TODO: - https://tangem.atlassian.net/browse/IOS-8316 | ||
let balanceInfoPublisher = networkService | ||
.getBalance(address: wallet.address) | ||
|
||
cancellable = balanceInfoPublisher | ||
.withWeakCaptureOf(self) | ||
.sink(receiveCompletion: { [weak self] result in | ||
switch result { | ||
case .failure(let error): | ||
self?.wallet.clearAmounts() | ||
completion(.failure(error)) | ||
case .finished: | ||
completion(.success(())) | ||
} | ||
}, receiveValue: { walletManager, balanceInfo in | ||
walletManager.updateWallet(balanceInfo: balanceInfo) | ||
}) | ||
} | ||
|
||
func getFee(amount: Amount, destination: String) -> AnyPublisher<[Fee], any Error> { | ||
|
@@ -32,4 +59,20 @@ class CasperWalletManager: BaseManager, WalletManager { | |
// TODO: - https://tangem.atlassian.net/browse/IOS-8316 | ||
return .anyFail(error: SendTxError(error: WalletError.empty)) | ||
} | ||
|
||
// MARK: - Private Implementation | ||
|
||
private func updateWallet(balanceInfo: CasperBalance) { | ||
if balanceInfo.value != wallet.amounts[.coin]?.value { | ||
wallet.clearPendingTransaction() | ||
} | ||
|
||
wallet.add(amount: Amount(with: wallet.blockchain, type: .coin, value: balanceInfo.value)) | ||
} | ||
} | ||
|
||
extension CasperWalletManager { | ||
enum Constants { | ||
static let constantFeeValue = Decimal(stringValue: "0.1") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Это юзается где-то? Нужна видимость internal? |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// | ||
// CasperNetworkRequest.QueryBalance.swift | ||
// BlockchainSdk | ||
// | ||
// Created by Alexander Skibin on 29.10.2024. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
extension CasperNetworkRequest { | ||
struct QueryBalance: Encodable { | ||
let purseIdentifier: PurseIdentifier | ||
} | ||
|
||
struct PurseIdentifier: Encodable { | ||
let mainPurseUnderPublicKey: String | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// | ||
// CasperNetworkRequest.swift | ||
// BlockchainSdk | ||
// | ||
// Created by Alexander Skibin on 29.10.2024. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
/// A top-level namespace. | ||
enum CasperNetworkRequest {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// | ||
// CasperNetworkResult.BalanceInfo.swift | ||
// BlockchainSdk | ||
// | ||
// Created by skibinalexander on 24.10.2024. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
extension CasperNetworkResponse { | ||
/// The balance represented in motes. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. А что это? Наименьшая атомарная единица? |
||
struct Balance: Decodable { | ||
let apiVersion: String | ||
let balance: String | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// | ||
// CasperNetworkResponse.swift | ||
// BlockchainSdk | ||
// | ||
// Created by skibinalexander on 24.10.2024. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
/// A top-level namespace. | ||
enum CasperNetworkResponse {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// | ||
// CasperBalance.swift | ||
// BlockchainSdk | ||
// | ||
// Created by skibinalexander on 24.10.2024. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct CasperBalance { | ||
let value: Decimal | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// | ||
// CasperNetworkProvider.swift | ||
// BlockchainSdk | ||
// | ||
// Created by skibinalexander on 22.10.2024. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import Combine | ||
import Foundation | ||
|
||
final class CasperNetworkProvider: HostProvider { | ||
var host: String { | ||
node.url.absoluteString | ||
} | ||
|
||
// MARK: - Private Properties | ||
|
||
private let node: NodeInfo | ||
private let provider: NetworkProvider<CasperTarget> | ||
|
||
// MARK: - Init | ||
|
||
init( | ||
node: NodeInfo, | ||
configuration: NetworkProviderConfiguration | ||
) { | ||
self.node = node | ||
provider = NetworkProvider<CasperTarget>(configuration: configuration) | ||
} | ||
|
||
// MARK: - Implementation | ||
|
||
func getBalance(address: String) -> AnyPublisher<CasperNetworkResponse.Balance, Error> { | ||
let query = CasperNetworkRequest.QueryBalance(purseIdentifier: .init(mainPurseUnderPublicKey: address)) | ||
return requestPublisher(for: .getBalance(data: query)) | ||
} | ||
|
||
// MARK: - Private Implementation | ||
|
||
private func requestPublisher<T: Decodable>(for type: CasperTarget.TargetType) -> AnyPublisher<T, Error> { | ||
let decoder = JSONDecoder() | ||
decoder.keyDecodingStrategy = .convertFromSnakeCase | ||
|
||
return provider.requestPublisher(CasperTarget(node: node, type: type)) | ||
.filterSuccessfulStatusAndRedirectCodes() | ||
.map(JSONRPC.Response<T, JSONRPC.APIError>.self, using: decoder) | ||
.tryMap { | ||
try $0.result.get() | ||
} | ||
.eraseToAnyPublisher() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// | ||
// CasperNetworkService.swift | ||
// BlockchainSdk | ||
// | ||
// Created by skibinalexander on 24.10.2024. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import Combine | ||
|
||
final class CasperNetworkService: MultiNetworkProvider { | ||
// MARK: - MultiNetwork Provider | ||
|
||
var currentProviderIndex: Int = 0 | ||
|
||
// MARK: - Properties | ||
|
||
let providers: [CasperNetworkProvider] | ||
let blockchainDecimalValue: Decimal | ||
|
||
// MARK: - Init | ||
|
||
init(providers: [CasperNetworkProvider], blockchainDecimalValue: Decimal) { | ||
self.providers = providers | ||
self.blockchainDecimalValue = blockchainDecimalValue | ||
} | ||
|
||
// MARK: - Implementation | ||
|
||
func getBalance(address: String) -> AnyPublisher<CasperBalance, Error> { | ||
return providerPublisher { provider in | ||
return provider | ||
.getBalance(address: address) | ||
.withWeakCaptureOf(self) | ||
.tryMap { service, result in | ||
guard let balanceValue = Decimal(string: result.balance) else { | ||
throw WalletError.failedToParseNetworkResponse() | ||
} | ||
|
||
let decimalBalanceValue = balanceValue / service.blockchainDecimalValue | ||
return .init(value: decimalBalanceValue) | ||
} | ||
.tryCatch { error -> AnyPublisher<CasperBalance, Error> in | ||
if let error = error as? JSONRPC.APIError, error.code == Constants.ERROR_CODE_QUERY_FAILED { | ||
return .anyFail( | ||
error: WalletError.noAccount( | ||
message: Localization.noAccountSendToCreate, | ||
amountToCreate: 0 | ||
) | ||
) | ||
} | ||
return .anyFail(error: error) | ||
} | ||
.eraseToAnyPublisher() | ||
} | ||
} | ||
} | ||
|
||
extension CasperNetworkService { | ||
enum Constants { | ||
static let ERROR_CODE_QUERY_FAILED = -32003 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// | ||
// CasperTarget.swift | ||
// BlockchainSdk | ||
// | ||
// Created by skibinalexander on 22.10.2024. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import Moya | ||
|
||
struct CasperTarget: TargetType { | ||
// MARK: - Properties | ||
|
||
let node: NodeInfo | ||
let type: TargetType | ||
|
||
// MARK: - Init | ||
|
||
init(node: NodeInfo, type: TargetType) { | ||
self.node = node | ||
self.type = type | ||
} | ||
|
||
// MARK: - TargetType | ||
|
||
var baseURL: URL { | ||
node.url | ||
} | ||
|
||
var path: String { | ||
"" | ||
} | ||
|
||
var method: Moya.Method { | ||
.post | ||
} | ||
|
||
var task: Task { | ||
switch type { | ||
case .getBalance(let data): | ||
let encoder = JSONEncoder() | ||
encoder.keyEncodingStrategy = .convertToSnakeCase | ||
|
||
return .requestJSONRPC( | ||
id: Constants.jsonRPCMethodId, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. id лучше глобально инкрементить (со есть хранить в static var и инкрементить при каждом чтении), чтобы в логах было проще матчить req и resp |
||
method: Method.queryBalance.rawValue, | ||
params: data, | ||
encoder: encoder | ||
) | ||
} | ||
} | ||
|
||
var headers: [String: String]? | ||
} | ||
|
||
extension CasperTarget { | ||
enum TargetType { | ||
case getBalance(data: CasperNetworkRequest.QueryBalance) | ||
} | ||
|
||
enum Method: String, Encodable { | ||
case queryBalance = "query_balance" | ||
} | ||
} | ||
|
||
private extension CasperTarget { | ||
enum Constants { | ||
static let jsonRPCMethodId: Int = 1 | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Опять этот метод убирания пендингов
Получения инфы по хешу транзы опять чтоль нету у этой сетки?