Skip to content

Commit

Permalink
Make use of result on completion (#221)
Browse files Browse the repository at this point in the history
- EthereumClient
- ThereumClient+Call
- JSONRPC
- EthereumClient+Static
- ERC20

Refactor ERC165

Refactor:

- ERC165
- ERC721
- Multicall

Refactor: EthereumNameService
  • Loading branch information
Dionysis Karatzas authored Jun 9, 2022
1 parent 9f7ab36 commit 2e3087a
Show file tree
Hide file tree
Showing 11 changed files with 1,360 additions and 831 deletions.
8 changes: 6 additions & 2 deletions web3sTests/Client/EthereumClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ class EthereumClientTests: XCTestCase {
_ = try await client?.eth_getBalance(address: EthereumAddress("0xnig42niog2"), block: .Latest)
XCTFail("Expected to throw while awaiting, but succeeded")
} catch {
XCTAssertEqual(error as? EthereumClientError, .unexpectedReturnValue)
XCTAssertEqual(error as? EthereumClientError, .executionError(
.init(code: -32602, message: "invalid argument 0: hex string has length 10, want 40 for common.Address", data: nil)
))
}
}

Expand Down Expand Up @@ -227,7 +229,9 @@ class EthereumClientTests: XCTestCase {
let _ = try await client?.eth_getTransaction(byHash: "0x01234")
XCTFail("Expected to throw while awaiting, but succeeded")
} catch {
XCTAssertEqual(error as? EthereumClientError, .unexpectedReturnValue)
XCTAssertEqual(error as? EthereumClientError, .executionError(
.init(code: -32602, message: "invalid argument 0: json: cannot unmarshal hex string of odd length into Go value of type common.Hash", data: nil)
))
}
}

Expand Down
114 changes: 77 additions & 37 deletions web3swift/src/Client/EthereumClient+Call.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ extension EthereumClient {
_ transaction: EthereumTransaction,
resolution: CallResolution = .noOffchain(failOnExecutionError: true),
block: EthereumBlock = .Latest,
completion: @escaping ((EthereumClientError?, String?) -> Void)
completionHandler: @escaping (Result<String, EthereumClientError>) -> Void
) {
guard let transactionData = transaction.data else {
return completion(EthereumClientError.noInputData, nil)
completionHandler(.failure(.noInputData))
return
}

struct CallParams: Encodable {
Expand Down Expand Up @@ -67,46 +68,51 @@ extension EthereumClient {
block: block.stringValue
)

EthereumRPC.execute(
session: session,
url: url,
method: "eth_call",
params: params,
receive: String.self
) { (error, response) in
if let resDataString = response as? String {
completion(nil, resDataString)
} else if case let .executionError(result) = error as? JSONRPCError {
switch resolution {
case .noOffchain:
completion(.executionError(result.error), nil)
case .offchainAllowed(let redirects):
if let lookup = result.offchainLookup, lookup.address == transaction.to {
self.offchainRead(
lookup: lookup,
maxReads: redirects
).sink(receiveCompletion: { offchainCompletion in
if case .failure = offchainCompletion {
completion(.noResultFound, nil)
EthereumRPC.execute(session: session,
url: url,
method: "eth_call",
params: params,
receive: String.self) { result in
switch result {
case .success(let data):
if let resDataString = data as? String {
completionHandler(.success(resDataString))
} else {
completionHandler(.failure(.unexpectedReturnValue))
}
case .failure(let error):
if case let .executionError(result) = error as? JSONRPCError {
switch resolution {
case .noOffchain:
completionHandler(.failure(.executionError(result.error)))
case .offchainAllowed(let redirects):
if let lookup = result.offchainLookup, lookup.address == transaction.to {
self.offchainRead(
lookup: lookup,
maxReads: redirects
).sink(receiveCompletion: { offchainCompletion in
if case .failure = offchainCompletion {
completionHandler(.failure(.noResultFound))
}
}, receiveValue: { data in
self.eth_call(
.init(
to: lookup.address,
data: lookup.encodeCall(withResponse: data)
),
resolution: .noOffchain(failOnExecutionError: true),
block: block, completionHandler: completionHandler
)
}
}, receiveValue: { data in
self.eth_call(
.init(
to: lookup.address,
data: lookup.encodeCall(withResponse: data)
),
resolution: .noOffchain(failOnExecutionError: true),
block: block, completion: completion
)
.store(in: &cancellables)
} else {
completionHandler(.failure(.executionError(result.error)))
}
)
.store(in: &cancellables)
} else {
completion(.executionError(result.error), nil)
}
} else {
completionHandler(.failure(.unexpectedReturnValue))
}
} else {
completion(.unexpectedReturnValue, nil)
}
}
}
Expand Down Expand Up @@ -211,6 +217,40 @@ extension EthereumClient {
}
}

// MARK: - Async/Await
extension EthereumClient {
public func eth_call(_ transaction: EthereumTransaction,
resolution: CallResolution = .noOffchain(failOnExecutionError: true),
block: EthereumBlock = .Latest) async throws -> String {
return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<String, Error>) in
eth_call(
transaction,
resolution: resolution,
block: block,
completionHandler: continuation.resume)
}
}
}

// MARK: - Deprecated
extension EthereumClient {
@available(*, deprecated, renamed: "eth_call(_:resolution:block:completionHandler:)")
public func eth_call( _ transaction: EthereumTransaction,
resolution: CallResolution = .noOffchain(failOnExecutionError: true),
block: EthereumBlock = .Latest,
completion: @escaping ((EthereumClientError?, String?) -> Void)
) {
eth_call(transaction, resolution: resolution, block: block) { result in
switch result {
case .success(let data):
completion(nil, data)
case .failure(let error):
completion(error, nil)
}
}
}
}

fileprivate struct OffchainReadJSONBody: Encodable {
let sender: EthereumAddress
let data: String
Expand Down
Loading

0 comments on commit 2e3087a

Please sign in to comment.