Skip to content

Commit

Permalink
Merge pull request #589 from yaroslavyaroslav/network-split
Browse files Browse the repository at this point in the history
Split library into modules
  • Loading branch information
yaroslavyaroslav authored Jul 19, 2022
2 parents 858135b + 4d655bd commit 7665ff5
Show file tree
Hide file tree
Showing 166 changed files with 1,749 additions and 1,560 deletions.
7 changes: 5 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,20 @@ let package = Package(
products: [
.library(name: "web3swift", targets: ["web3swift"])
],

dependencies: [
.package(url: "https://github.com/attaswift/BigInt.git", from: "5.3.0"),
.package(url: "https://github.com/daltoniam/Starscream.git", from: "4.0.4"),
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "1.5.1")
],
targets: [
.target(name: "secp256k1"),
.target(
name: "Core",
dependencies: ["BigInt", "secp256k1", "CryptoSwift"]
),
.target(
name: "web3swift",
dependencies: ["BigInt", "secp256k1", "Starscream", "CryptoSwift"],
dependencies: ["Core", "BigInt", "secp256k1", "Starscream"],
exclude: excludeFiles,
resources: [
.copy("./Browser/browser.js"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,20 @@ extension EthereumAddress {

}

extension EthereumAddress: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let stringValue = try container.decode(String.self)
self.init(stringValue)!
}

public func encode(to encoder: Encoder) throws {
let value = self.address.lowercased()
var signleValuedCont = encoder.singleValueContainer()
try signleValuedCont.encode(value)
}
}

extension EthereumAddress: Hashable { }

extension EthereumAddress: APIResultType { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//
// APIRequest+ComputedProperties.swift
//
//
// Created by Yaroslav Yashin on 12.07.2022.
//

import Foundation

extension APIRequest {
var method: REST {
switch self {
default: return .POST
}
}

public var encodedBody: Data {
let request = RequestBody(method: self.call, params: self.parameters)
// this is safe to force try this here
// Because request must failed to compile if it not conformable with `Encodable` protocol
return try! JSONEncoder().encode(request)
}

var parameters: [RequestParameter] {
switch self {
case .gasPrice, .blockNumber, .getNetwork, .getAccounts, .getTxPoolStatus, .getTxPoolContent, .getTxPoolInspect:
return [RequestParameter]()

case .estimateGas(let transactionParameters, let blockNumber):
return [.transaction(transactionParameters), .string(blockNumber.stringValue)]

case let .sendRawTransaction(hash):
return [.string(hash)]

case let .sendTransaction(transactionParameters):
return [.transaction(transactionParameters)]

case .getTransactionByHash(let hash):
return [.string(hash)]

case .getTransactionReceipt(let receipt):
return [.string(receipt)]

case .getLogs(let eventFilterParameters):
return [.eventFilter(eventFilterParameters)]

case .personalSign(let address, let string):
return [.string(address), .string(string)]

case .call(let transactionParameters, let blockNumber):
return [.transaction(transactionParameters), .string(blockNumber.stringValue)]

case .getTransactionCount(let address, let blockNumber):
return [.string(address), .string(blockNumber.stringValue)]

case .getBalance(let address, let blockNumber):
return [.string(address), .string(blockNumber.stringValue)]

case .getStorageAt(let address, let bigUInt, let blockNumber):
return [.string(address), .string(bigUInt.hexString), .string(blockNumber.stringValue)]

case .getCode(let address, let blockNumber):
return [.string(address), .string(blockNumber.stringValue)]

case .getBlockByHash(let hash, let bool):
return [.string(hash), .bool(bool)]

case .getBlockByNumber(let block, let bool):
return [.string(block.stringValue), .bool(bool)]

case .feeHistory(let uInt, let blockNumber, let array):
return [.string(uInt.hexString), .string(blockNumber.stringValue), .doubleArray(array)]

case .createAccount(let string):
return [.string(string)]

case .unlockAccount(let address, let string, let uInt):
return [.string(address), .string(string), .uint(uInt ?? 0)]
}
}

public var call: String {
switch self {
case .gasPrice: return "eth_gasPrice"
case .blockNumber: return "eth_blockNumber"
case .getNetwork: return "net_version"
case .getAccounts: return "eth_accounts"
case .sendRawTransaction: return "eth_sendRawTransaction"
case .sendTransaction: return "eth_sendTransaction"
case .getTransactionByHash: return "eth_getTransactionByHash"
case .getTransactionReceipt: return "eth_getTransactionReceipt"
case .personalSign: return "eth_sign"
case .getLogs: return "eth_getLogs"
case .call: return "eth_call"
case .estimateGas: return "eth_estimateGas"
case .getTransactionCount: return "eth_getTransactionCount"
case .getBalance: return "eth_getBalance"
case .getStorageAt: return "eth_getStorageAt"
case .getCode: return "eth_getCode"
case .getBlockByHash: return "eth_getBlockByHash"
case .getBlockByNumber: return "eth_getBlockByNumber"
case .feeHistory: return "eth_feeHistory"

case .unlockAccount: return "personal_unlockAccount"
case .createAccount: return "personal_createAccount"
case .getTxPoolStatus: return "txpool_status"
case .getTxPoolContent: return "txpool_content"
case .getTxPoolInspect: return "txpool_inspect"
}
}
}
49 changes: 49 additions & 0 deletions Sources/Core/EthereumNetwork/Request/APIRequest+Methods.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// APIRequest+Methods.swift
//
//
// Created by Yaroslav Yashin on 12.07.2022.
//

import Foundation
import BigInt

extension APIRequest {
public static func sendRequest<Result>(with provider: Web3Provider, for call: APIRequest) async throws -> APIResponse<Result> {
let request = setupRequest(for: call, with: provider)
return try await APIRequest.send(uRLRequest: request, with: provider.session)
}

static func setupRequest(for call: APIRequest, with provider: Web3Provider) -> URLRequest {
var urlRequest = URLRequest(url: provider.url, cachePolicy: .reloadIgnoringCacheData)
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.setValue("application/json", forHTTPHeaderField: "Accept")
urlRequest.httpMethod = call.method.rawValue
urlRequest.httpBody = call.encodedBody
return urlRequest
}

public static func send<Result>(uRLRequest: URLRequest, with session: URLSession) async throws -> APIResponse<Result> {
let (data, response) = try await session.data(for: uRLRequest)

guard 200 ..< 400 ~= response.statusCode else {
if 400 ..< 500 ~= response.statusCode {
throw Web3Error.clientError(code: response.statusCode)
} else {
throw Web3Error.serverError(code: response.statusCode)
}
}

/// This bit of code is purposed to work with literal types that comes in Response in hexString type.
/// Currently it's just `Data` and any kind of Integers `(U)Int`, `Big(U)Int`.
if Result.self == Data.self || Result.self == UInt.self || Result.self == Int.self || Result.self == BigInt.self || Result.self == BigUInt.self {
guard let LiteralType = Result.self as? LiteralInitiableFromString.Type else { throw Web3Error.typeError }
guard let responseAsString = try? JSONDecoder().decode(APIResponse<String>.self, from: data) else { throw Web3Error.dataError }
guard let literalValue = LiteralType.init(from: responseAsString.result) else { throw Web3Error.dataError }
/// `Literal` conforming `LiteralInitiableFromString`, that conforming to an `APIResponseType` type, so it's never fails.
guard let result = literalValue as? Result else { throw Web3Error.typeError }
return APIResponse(id: responseAsString.id, jsonrpc: responseAsString.jsonrpc, result: result)
}
return try JSONDecoder().decode(APIResponse<Result>.self, from: data)
}
}
28 changes: 28 additions & 0 deletions Sources/Core/EthereumNetwork/Request/APIRequest+UtilityTypes.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// APIRequest+UtilityTypes.swift
//
//
// Created by Yaroslav Yashin on 12.07.2022.
//

import Foundation

/// JSON RPC response structure for serialization and deserialization purposes.
public struct APIResponse<Result>: Decodable where Result: APIResultType {
public var id: Int
public var jsonrpc = "2.0"
public var result: Result
}

enum REST: String {
case POST
case GET
}

struct RequestBody: Encodable {
var jsonrpc = "2.0"
var id = Counter.increment()

var method: String
var params: [RequestParameter]
}
Loading

0 comments on commit 7665ff5

Please sign in to comment.