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

Fetch balance + Cleanup #23

Merged
merged 1 commit into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions Sample/Example.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Example/Example.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2;
CURRENT_PROJECT_VERSION = 5;
DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\"";
DEVELOPMENT_TEAM = W5R8AG9K22;
ENABLE_HARDENED_RUNTIME = YES;
Expand Down Expand Up @@ -364,7 +364,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Example/Example.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2;
CURRENT_PROJECT_VERSION = 5;
DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\"";
DEVELOPMENT_TEAM = W5R8AG9K22;
ENABLE_HARDENED_RUNTIME = YES;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"location" : "https://github.com/WalletConnect/WalletConnectSwiftV2",
"state" : {
"branch" : "remove-wcm",
"revision" : "0085250fd993f40a638f8d3e300f4af8cbf9e7a8"
"revision" : "04bcc547a61768598286cfa4cb0a06c0475c4d35"
}
}
],
Expand Down
91 changes: 88 additions & 3 deletions Sources/Web3Modal/Core/BlockchainAPIInteractor.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import Foundation
import HTTPClient

import JSONRPC

final class BlockchainAPIInteractor: ObservableObject {

private let store: Store

init(store: Store = .shared) {
self.store = store
}

func getIdentity() async throws {

let account = store.session?.accounts.first
let address = account?.address
let chainId = account?.blockchainIdentifier
Expand All @@ -31,10 +31,95 @@ final class BlockchainAPIInteractor: ObservableObject {
self.store.identity = response
}
}

func getBalance() async throws {
enum GetBalanceError: Error {
case noAddress, invalidValue, noChain
}

guard let address = store.session?.accounts.first?.address else {
throw GetBalanceError.noAddress
}

guard let chain = store.selectedChain else {
throw GetBalanceError.noChain
}

let request = RPCRequest(
method: "eth_getBalance", params: [
address, "latest"
]
)

var urlRequest = URLRequest(url: URL(string: chain.rpcUrl)!)
urlRequest.httpMethod = "POST"
urlRequest.httpBody = try JSONEncoder().encode(request)
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")

let (data, _) = try await URLSession.shared.data(for: urlRequest)
let decodedResponse = try JSONDecoder().decode(RPCResponse.self, from: data)
let weiFactor = pow(10, chain.token.decimal)

guard let decimalValue = try decodedResponse.result?
.get(String.self)
.convertBalanceHexToBigDecimal()?
.toWei(weiFactor: weiFactor)
else {
throw GetBalanceError.invalidValue
}

let doubleValue = Double(truncating: decimalValue as NSNumber)

DispatchQueue.main.async {
self.store.balance = doubleValue
}
}
}


struct Identity: Codable {
let name: String?
let avatar: String?
}

struct BalanceRequest: Encodable {
init(address: String) {
self.address = address

self.id = RPCID()
self.params = [
address, "latest"
]
}

let address: String
let id: RPCID
let jsonrpc: String = "2.0"
let method: String = "eth_getBalance"
let params: [String]
}

struct BalanceRpcResponse: Codable {
let id: RPCID
let jsonrpc: String
let result: String?
let error: RpcError?

struct RpcError: Codable {
let code: Int
let message: String
}
}

private extension String {
func convertBalanceHexToBigDecimal() -> Decimal? {
let substring = dropFirst(2)
guard let longValue = UInt64(substring, radix: 16) else { return nil }
return Decimal(string: "\(longValue)")
}
}

extension Decimal {
func toWei(weiFactor: Decimal) -> Decimal {
return self / weiFactor
}
}
8 changes: 7 additions & 1 deletion Sources/Web3Modal/Core/SignInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ class SignInteractor: ObservableObject {
}
}

try await Web3Modal.instance.disconnect(topic: store.session?.topic ?? "")
do {
try await Web3Modal.instance.disconnect(topic: store.session?.topic ?? "")
} catch {
print(error.localizedDescription)
}
try await Web3Modal.instance.cleanup()
try await createPairingAndConnect()
}
}
38 changes: 37 additions & 1 deletion Sources/Web3Modal/Core/W3MAPIInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ final class W3MAPIInteractor: ObservableObject {
request.setValue("ios-3.0.0-alpha.0", forHTTPHeaderField: "x-sdk-version")

do {
let (data, _) = try await URLSession(configuration: .ephemeral).data(for: request)
let (data, _) = try await URLSession.shared.data(for: request)
return (wallet.imageId, UIImage(data: data))
} catch {
print(error.localizedDescription)
Expand All @@ -125,4 +125,40 @@ final class W3MAPIInteractor: ObservableObject {
}
}
}

func prefetchChainImages() async throws {
var chainImages: [String: UIImage] = [:]

try await ChainsPresets.ethChains.concurrentMap { chain in

let url = URL(string: "https://api.web3modal.com/public/getAssetImage/\(chain.imageId)")!
var request = URLRequest(url: url)

request.setValue(Web3Modal.config.projectId, forHTTPHeaderField: "x-project-id")
request.setValue("w3m", forHTTPHeaderField: "x-sdk-type")
request.setValue("ios-3.0.0-alpha.0", forHTTPHeaderField: "x-sdk-version")

do {
let (data, _) = try await URLSession.shared.data(for: request)
return (chain.imageId, UIImage(data: data))
} catch {
print(error.localizedDescription)
}

return ("", UIImage?.none)
}
.forEach { key, value in
if value == nil {
return
}

chainImages[key] = value
}

DispatchQueue.main.async { [chainImages] in
self.store.chainImages.merge(chainImages) { _, new in
new
}
}
}
}
36 changes: 25 additions & 11 deletions Sources/Web3Modal/Core/Web3Modal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import SwiftUI
import WalletConnectSign
import WalletConnectVerify


#if canImport(UIKit)
import UIKit
#endif
Expand All @@ -29,10 +28,25 @@ public class Web3Modal {
guard let config = Web3Modal.config else {
fatalError("Error - you must call Web3Modal.configure(_:) before accessing the shared instance.")
}
return Web3ModalClient(

let client = Web3ModalClient(
signClient: Sign.instance,
pairingClient: Pair.instance as! (PairingClientProtocol & PairingInteracting & PairingRegisterer)
)

if let session = client.getSessions().first {
Store.shared.session = session

if let blockchain = session.accounts.first?.blockchain {
let matchingChain = ChainsPresets.ethChains.first(where: {
$0.chainNamespace == blockchain.namespace && $0.chainReference == blockchain.reference
})

Store.shared.selectedChain = matchingChain
}
}

return client
}()

struct Config {
Expand Down Expand Up @@ -68,7 +82,12 @@ public class Web3Modal {
includeWebWallets: includeWebWallets,
recommendedWalletIds: recommendedWalletIds,
excludedWalletIds: excludedWalletIds
)
)

Task {
try? await W3MAPIInteractor().fetchFeaturedWallets()
try? await W3MAPIInteractor().prefetchChainImages()
}
}

public static func set(sessionParams: SessionParams) {
Expand All @@ -79,7 +98,6 @@ public class Web3Modal {
#if canImport(UIKit)

extension Web3Modal {

public static func present(from presentingViewController: UIViewController? = nil) {
guard let vc = presentingViewController ?? topViewController() else {
assertionFailure("No controller found for presenting modal")
Expand All @@ -91,7 +109,6 @@ extension Web3Modal {
}

private static func topViewController(_ base: UIViewController? = nil) -> UIViewController? {

let base = base ?? UIApplication
.shared
.connectedScenes
Expand Down Expand Up @@ -121,10 +138,8 @@ extension Web3Modal {

import AppKit

extension Web3Modal {

public static func present(from presentingViewController: NSViewController? = nil) {

public extension Web3Modal {
static func present(from presentingViewController: NSViewController? = nil) {
let modal = Web3ModalSheetController()
presentingViewController!.presentAsModalWindow(modal)
}
Expand All @@ -137,7 +152,7 @@ public struct SessionParams {
public let optionalNamespaces: [String: ProposalNamespace]?
public let sessionProperties: [String: String]?

public init(requiredNamespaces: [String : ProposalNamespace], optionalNamespaces: [String : ProposalNamespace]? = nil, sessionProperties: [String : String]? = nil) {
public init(requiredNamespaces: [String: ProposalNamespace], optionalNamespaces: [String: ProposalNamespace]? = nil, sessionProperties: [String: String]? = nil) {
self.requiredNamespaces = requiredNamespaces
self.optionalNamespaces = optionalNamespaces
self.sessionProperties = sessionProperties
Expand All @@ -162,4 +177,3 @@ public struct SessionParams {
)
}()
}

1 change: 1 addition & 0 deletions Sources/Web3Modal/Networking/Web3ModalAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ enum Web3ModalAPI: HTTPService {
"search": params.search ?? "",
"recommendedIds": params.recommendedIds.joined(separator: ","),
"excludedIds": params.excludedIds.joined(separator: ","),
"platform": "ios",
]
.compactMapValues { value in
value.isEmpty ? nil : value
Expand Down
78 changes: 78 additions & 0 deletions Sources/Web3Modal/Screens/ChainSwitch/WhatIsNetworkView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import SwiftUI
import Web3ModalUI

struct WhatIsNetworkView: View {

@Environment(\.verticalSizeClass) var verticalSizeClass

@EnvironmentObject var router: Router

var body: some View {
content()
.onAppear {
UIPageControl.appearance().currentPageIndicatorTintColor = UIColor(Color.Foreground100)
UIPageControl.appearance().pageIndicatorTintColor = UIColor(Color.Foreground100).withAlphaComponent(0.2)
}
}

func content() -> some View {
VStack(spacing: 0) {
if verticalSizeClass == .compact {
TabView {
ForEach(sections(), id: \.title) { section in
section
.padding(.bottom, 40)
}
}
.transform {
#if os(iOS)
$0.tabViewStyle(.page(indexDisplayMode: .always))
#endif
}
.scaledToFill()
.layoutPriority(1)

} else {
ForEach(sections(), id: \.title) { section in
section
.padding(.bottom, Spacing.s)
}
}

Button(action: {
router.navigateToExternalLink(URL(string: "https://ethereum.org/en/developers/docs/networks/")!)
}) {
HStack {
Text("Learn More")
Image.ExternalLink
}
}
.buttonStyle(W3MButtonStyle(size: .m))
}
.padding(.vertical, Spacing.xxl)
.padding(.horizontal, Spacing.xl)
}

func sections() -> [HelpSection] {
[
HelpSection(
title: "The system’s nuts and bolts",
description: "A network is what brings the blockchain to life, as this technical infrastructure allows apps to access the ledger and smart contract services.",
assets: [.imageNetwork, .imageLayers, .imageSystem]
),
HelpSection(
title: "Designed for different uses",
description: "Each network is designed differently, and may therefore suit certain apps and experiences.",
assets: [.imageNoun, .imageDefiAlt, .imageDao]
),
]
}
}

#if DEBUG
struct WhatIsNetworkView_Previews: PreviewProvider {
static var previews: some View {
WhatIsNetworkView()
}
}
#endif
7 changes: 1 addition & 6 deletions Sources/Web3Modal/Screens/ConnectWallet/GetAWalletView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,7 @@ struct GetAWalletView: View {
})
.buttonStyle(W3MListSelectStyle(
imageContent: { _ in
W3MAllWalletsImage(images: [
.init(image: Image("MockWalletImage", bundle: .UIModule), walletName: "Metamask"),
.init(image: Image("MockWalletImage", bundle: .UIModule), walletName: "Trust"),
.init(image: Image("MockWalletImage", bundle: .UIModule), walletName: "Safe"),
.init(image: Image("MockWalletImage", bundle: .UIModule), walletName: "Rainbow"),
])
Image.optionAll
}
))
}
Expand Down
Loading