Skip to content
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

Open
wants to merge 19 commits into
base: blockchains/casper/IOS-8332_make_casper_address_service
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
573bfab
IOS-8316 Add network provider casper and balance method
skibinalexander Oct 24, 2024
44b66b7
IOS-8316 Merge branch 'blockchains/casper/IOS-8332_make_casper_addres…
skibinalexander Oct 25, 2024
b4484da
IOS-8316 Merge with IOS-8316
skibinalexander Oct 29, 2024
f669a4b
IOS-8316 Merge branch 'blockchains/casper/IOS-8332_make_casper_addres…
skibinalexander Oct 29, 2024
9d28bd7
IOS-8316 Finalize obtain balance casper
skibinalexander Oct 29, 2024
0ba1c6e
Merge branch 'blockchains/casper/IOS-8332_make_casper_address_service…
skibinalexander Oct 30, 2024
6c5bd35
IOS-8316 Complete obtain balance value
skibinalexander Oct 30, 2024
ff058fd
Merge branch 'blockchains/casper/IOS-8332_make_casper_address_service…
skibinalexander Oct 30, 2024
63c81c8
Merge branch 'blockchains/casper/IOS-8332_make_casper_address_service…
skibinalexander Oct 30, 2024
da89400
Merge branch 'blockchains/casper/IOS-8332_make_casper_address_service…
skibinalexander Oct 31, 2024
60369ee
Merge branch 'blockchains/casper/IOS-8332_make_casper_address_service…
skibinalexander Nov 1, 2024
f643792
Merge branch 'blockchains/casper/IOS-8332_make_casper_address_service…
skibinalexander Nov 2, 2024
dcfcd27
Merge branch 'blockchains/casper/IOS-8332_make_casper_address_service…
skibinalexander Nov 4, 2024
f9cd1f7
IOS-8316 Correct address network service
skibinalexander Nov 4, 2024
c9600ec
Merge branch 'blockchains/casper/IOS-8332_make_casper_address_service…
skibinalexander Nov 4, 2024
4afdfbd
Merge branch 'blockchains/casper/IOS-8332_make_casper_address_service…
skibinalexander Nov 5, 2024
051842c
Merge branch 'blockchains/casper/IOS-8332_make_casper_address_service…
skibinalexander Nov 5, 2024
2f4785e
Merge branch 'blockchains/casper/IOS-8332_make_casper_address_service…
skibinalexander Nov 5, 2024
a6aa213
Merge branch 'blockchains/casper/IOS-8332_make_casper_address_service…
skibinalexander Nov 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ extension CasperAddressService {

// MARK: - Helpers

fileprivate extension String {
private extension String {
func isSameCase() -> Bool {
lowercased() == self || uppercased() == self
}
Expand Down
14 changes: 13 additions & 1 deletion BlockchainSdk/Blockchains/Casper/CasperWalletAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ import Foundation

struct CasperWalletAssembly: WalletManagerAssembly {
func make(with input: WalletManagerAssemblyInput) throws -> WalletManager {
CasperWalletManager(wallet: input.wallet)
CasperWalletManager(
wallet: input.wallet,
networkService: CasperNetworkService(
providers: APIResolver(blockchain: input.blockchain, config: input.blockchainSdkConfig)
.resolveProviders(apiInfos: input.apiInfo) { nodeInfo, _ in
CasperNetworkProvider(
node: nodeInfo,
configuration: input.networkConfig
)
},
blockchainDecimalValue: input.blockchain.decimalValue
)
)
}
}
49 changes: 46 additions & 3 deletions BlockchainSdk/Blockchains/Casper/CasperWalletManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Опять этот метод убирания пендингов
Получения инфы по хешу транзы опять чтоль нету у этой сетки?

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")
Copy link
Contributor

Choose a reason for hiding this comment

The 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
}
}
12 changes: 12 additions & 0 deletions BlockchainSdk/Blockchains/Casper/DTO/CasperNetworkRequest.swift
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.
Copy link
Contributor

Choose a reason for hiding this comment

The 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 {}
13 changes: 13 additions & 0 deletions BlockchainSdk/Blockchains/Casper/Domain/CasperBalance.swift
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
}
}
71 changes: 71 additions & 0 deletions BlockchainSdk/Blockchains/Casper/Network/CasperTarget.swift
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,
Copy link
Contributor

Choose a reason for hiding this comment

The 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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ struct NowNodesAPIResolver {
link = "https://blast.nownodes.io/\(apiKey)"
case .filecoin:
link = "https://fil.nownodes.io/\(apiKey)/rpc/v1"
case .casper:
link = "https://casper.nownodes.io/\(apiKey)/rpc"
default:
return nil
}
Expand Down
Loading