Skip to content

Commit

Permalink
feature: add ability to specify read-only rpc map (#185)
Browse files Browse the repository at this point in the history
* feat: add readOnlyRpcMap option

* update unit tests

* Update README with read only rpc documentation
  • Loading branch information
elefantel authored Sep 9, 2024
1 parent 4bdd6d9 commit dbbcba7
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 129 deletions.
21 changes: 18 additions & 3 deletions Example/Tests/EthereumConnectTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class EthereumConnectTests: XCTestCase {
var trackEventMock: ((Event, [String: Any]) -> Void)!
var ethereum: Ethereum!
var store: SecureStore!
var mockNetwork: MockNetwork!
var mockReadOnlyRPCProvider: MockReadOnlyRPCProvider!

override func setUp() {
super.setUp()
Expand All @@ -23,10 +25,13 @@ class EthereumConnectTests: XCTestCase {
trackEventMock = { _, _ in }
EthereumWrapper.shared.ethereum = nil
SDKWrapper.shared.sdk = nil
mockNetwork = MockNetwork()
mockReadOnlyRPCProvider = MockReadOnlyRPCProvider(infuraAPIKey: "12345", readonlyRPCMap: [:], network: mockNetwork)
ethereum = Ethereum.shared(
transport: .socket,
store: store,
commClientFactory: commClientFactory,
commClientFactory: commClientFactory,
readOnlyRPCProvider: mockReadOnlyRPCProvider,
trackEvent: trackEventMock)
}

Expand All @@ -43,8 +48,18 @@ class EthereumConnectTests: XCTestCase {

// Test the singleton instance creation
func testSingletonInstance() {
let instance1 = Ethereum.shared(transport: .socket, store: store, commClientFactory: commClientFactory, trackEvent: trackEventMock)
let instance2 = Ethereum.shared(transport: .socket, store: store, commClientFactory: commClientFactory, trackEvent: trackEventMock)
let instance1 = Ethereum.shared(
transport: .socket,
store: store,
commClientFactory: commClientFactory,
readOnlyRPCProvider: mockReadOnlyRPCProvider,
trackEvent: trackEventMock)
let instance2 = Ethereum.shared(
transport: .socket,
store: store,
commClientFactory: commClientFactory,
readOnlyRPCProvider: mockReadOnlyRPCProvider,
trackEvent: trackEventMock)
XCTAssert(instance1 === instance2)
}

Expand Down
43 changes: 24 additions & 19 deletions Example/Tests/EthereumConvenienceMethodsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class EthereumConvenienceMethodsTests: XCTestCase {
var mockEthereumDelegate: MockEthereumDelegate!
var trackEventMock: ((Event, [String: Any]) -> Void)!
var ethereum: Ethereum!
var mockInfuraProvider: MockInfuraProvider!
var mockReadOnlyRPCProvider: MockReadOnlyRPCProvider!
let infuraApiKey = "testApiKey"
var store: SecureStore!
var trackedEvents: [(Event, [String: Any])] = []
Expand All @@ -27,15 +27,18 @@ class EthereumConvenienceMethodsTests: XCTestCase {

store = Keychain(service: "com.example.ethconvenience")
mockNetwork = MockNetwork()
mockInfuraProvider = MockInfuraProvider(infuraAPIKey: infuraApiKey, network: mockNetwork)
mockReadOnlyRPCProvider = MockReadOnlyRPCProvider(
infuraAPIKey: infuraApiKey,
readonlyRPCMap: [:],
network: mockNetwork)
mockEthereumDelegate = MockEthereumDelegate()
EthereumWrapper.shared.ethereum = nil
SDKWrapper.shared.sdk = nil
ethereum = Ethereum.shared(
transport: .socket,
store: store,
commClientFactory: mockCommClientFactory,
infuraProvider: mockInfuraProvider,
readOnlyRPCProvider: mockReadOnlyRPCProvider,
trackEvent: trackEventMock)
ethereum.delegate = mockEthereumDelegate
}
Expand All @@ -46,7 +49,7 @@ class EthereumConvenienceMethodsTests: XCTestCase {
mockNetwork = nil
store.deleteAll()
mockEthereumDelegate = nil
mockInfuraProvider = nil
mockReadOnlyRPCProvider = nil
mockCommClientFactory = nil
EthereumWrapper.shared.ethereum = nil
SDKWrapper.shared.sdk = nil
Expand All @@ -55,93 +58,93 @@ class EthereumConvenienceMethodsTests: XCTestCase {

func testGetChainId() async {
ethereum.connected = true
ethereum.infuraProvider = nil
let chainId = "0x1"

let expectation = self.expectation(description: "Request should return chainId")
performSuccessfulTask(
ethereum.getChainId,
expectedValue: chainId,
expectation: expectation)
mockReadOnlyRPCProvider.expectation = expectation
sendResultAndAwait(chainId, method: .ethChainId)
await fulfillment(of: [expectation], timeout: 2.0)
}

func testGetEthAccounts() async {
ethereum.connected = true
ethereum.infuraProvider = nil
let accounts = ["0x1234"]

let expectation = self.expectation(description: "Request should return accounts")
performSuccessfulTaskCollectionResult(
ethereum.getEthAccounts,
expectedValue: accounts,
expectation: expectation)
mockReadOnlyRPCProvider.expectation = expectation
sendResultAndAwait(accounts, method: .ethAccounts)
await fulfillment(of: [expectation], timeout: 2.0)
}

func testGetEthGasPrice() async {
ethereum.connected = true
ethereum.infuraProvider = nil
let balance = "0x1000"

let expectation = self.expectation(description: "Request should return gas price")
performSuccessfulTask(ethereum.getEthGasPrice,
expectedValue: balance,
expectation: expectation)
mockReadOnlyRPCProvider.expectation = expectation
sendResultAndAwait(balance, method: .ethGasPrice)
await fulfillment(of: [expectation], timeout: 2.0)
}

func testGetEthBalance() async {
ethereum.connected = true
ethereum.infuraProvider = nil
let balance = "0x1000"

let expectation = self.expectation(description: "Request should return balance")
performSuccessfulTask({
await self.ethereum.getEthBalance(address: "0x1234", block: "latest")
}, expectedValue: balance, expectation: expectation)
mockReadOnlyRPCProvider.expectation = expectation
sendResultAndAwait(balance, method: .ethGetBalance)
await fulfillment(of: [expectation], timeout: 2.0)
}

func testGetEthBlockNumber() async {
ethereum.connected = true
ethereum.infuraProvider = nil
let blockNumber = "0x10"

let expectation = self.expectation(description: "Request should return block number")
performSuccessfulTask({
await self.ethereum.getEthBlockNumber()
}, expectedValue: blockNumber, expectation: expectation)
mockReadOnlyRPCProvider.expectation = expectation
sendResultAndAwait(blockNumber, method: .ethBlockNumber)
await fulfillment(of: [expectation], timeout: 2.0)
}

func testGetEthEstimateGas() async {
ethereum.connected = true
ethereum.infuraProvider = nil
let gasEstimate = "0x5208"

let expectation = self.expectation(description: "Request should return gas estimate")
performSuccessfulTask({
await self.ethereum.getEthEstimateGas()
}, expectedValue: gasEstimate, expectation: expectation)
mockReadOnlyRPCProvider.expectation = expectation
sendResultAndAwait(gasEstimate, method: .ethEstimateGas)
await fulfillment(of: [expectation], timeout: 2.0)
}

func testGetWeb3ClientVersion() async {
ethereum.connected = true
ethereum.infuraProvider = nil
let web3Version = "Geth/v1.8.23-stable"

let expectation = self.expectation(description: "Request should return web3 version")
performSuccessfulTask({
await self.ethereum.getWeb3ClientVersion()
}, expectedValue: web3Version, expectation: expectation)
mockReadOnlyRPCProvider.expectation = expectation
sendResultAndAwait(web3Version, method: .web3ClientVersion)
await fulfillment(of: [expectation], timeout: 2.0)
}
Expand Down Expand Up @@ -184,52 +187,54 @@ class EthereumConvenienceMethodsTests: XCTestCase {

func testSendRawTransaction() async {
ethereum.connected = true
ethereum.infuraProvider = nil
let transactionHash = "0x345678"

let expectation = self.expectation(description: "Request should return transaction hash result")
performSuccessfulTask({
await self.ethereum.sendRawTransaction(signedTransaction: "signedTx")
}, expectedValue: transactionHash, expectation: expectation)
mockReadOnlyRPCProvider.response = transactionHash
mockReadOnlyRPCProvider.expectation = expectation
sendResultAndAwait(transactionHash, method: .ethSendRawTransaction)
await fulfillment(of: [expectation], timeout: 2.0)
}

func testGetBlockTransactionCountByNumber() async {
ethereum.connected = true
ethereum.infuraProvider = nil
let transactionCount = "0x20"

let expectation = self.expectation(description: "Request should return transaction count")
mockReadOnlyRPCProvider.response = transactionCount

performSuccessfulTask({
await self.ethereum.getBlockTransactionCountByNumber(blockNumber: "0x10")
}, expectedValue: transactionCount, expectation: expectation)

sendResultAndAwait(transactionCount, method: .ethGetBlockTransactionCountByNumber)
await fulfillment(of: [expectation], timeout: 2.0)
await fulfillment(of: [expectation], timeout: 20.0)
}

func testGetBlockTransactionCountByHash() async {
ethereum.connected = true
ethereum.infuraProvider = nil
let transactionCount = "0x30"

let expectation = self.expectation(description: "Request should return transaction count")
performSuccessfulTask({
await self.ethereum.getBlockTransactionCountByHash(blockHash: "0xabcdef")
}, expectedValue: transactionCount, expectation: expectation)
mockReadOnlyRPCProvider.response = transactionCount
mockReadOnlyRPCProvider.expectation = expectation
sendResultAndAwait(transactionCount, method: .ethGetBlockTransactionCountByHash)
await fulfillment(of: [expectation], timeout: 2.0)
}

func testGetTransactionCount() async {
ethereum.connected = true
ethereum.infuraProvider = nil
let transactionCount = "0x40"

let expectation = self.expectation(description: "Request should return transaction count")
performSuccessfulTask({
await self.ethereum.getTransactionCount(address: "0x1234", tagOrblockNumber: "latest")
}, expectedValue: transactionCount, expectation: expectation)
let result = await self.ethereum.getTransactionCount(address: "0x1234", tagOrblockNumber: "latest")
mockReadOnlyRPCProvider.response = transactionCount
sendResultAndAwait(transactionCount, method: .ethGetTransactionCount)
await fulfillment(of: [expectation], timeout: 2.0)
}
Expand Down
27 changes: 14 additions & 13 deletions Example/Tests/EthereumTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class EthereumTests: XCTestCase {
var mockEthereumDelegate: MockEthereumDelegate!
var trackEventMock: ((Event, [String: Any]) -> Void)!
var ethereum: Ethereum!
var mockInfuraProvider: MockInfuraProvider!
var mockReadOnlyRPCProvider: MockReadOnlyRPCProvider!
let infuraApiKey = "testApiKey"
var cancellables: Set<AnyCancellable>!
var trackedEvents: [(Event, [String: Any])] = []
Expand All @@ -29,15 +29,18 @@ class EthereumTests: XCTestCase {
}

mockNetwork = MockNetwork()
mockInfuraProvider = MockInfuraProvider(infuraAPIKey: infuraApiKey, network: mockNetwork)
mockReadOnlyRPCProvider = MockReadOnlyRPCProvider(
infuraAPIKey: infuraApiKey,
readonlyRPCMap: nil,
network: mockNetwork)
mockEthereumDelegate = MockEthereumDelegate()
EthereumWrapper.shared.ethereum = nil
SDKWrapper.shared.sdk = nil
ethereum = Ethereum.shared(
transport: .socket,
store: store,
commClientFactory: mockCommClientFactory,
infuraProvider: mockInfuraProvider,
readOnlyRPCProvider: mockReadOnlyRPCProvider,
trackEvent: trackEventMock)
ethereum.delegate = mockEthereumDelegate
}
Expand All @@ -49,7 +52,7 @@ class EthereumTests: XCTestCase {
ethereum = nil
mockNetwork = nil
mockEthereumDelegate = nil
mockInfuraProvider = nil
mockReadOnlyRPCProvider = nil
mockCommClientFactory = nil
EthereumWrapper.shared.ethereum = nil
SDKWrapper.shared.sdk = nil
Expand All @@ -60,11 +63,11 @@ class EthereumTests: XCTestCase {
let expectation = self.expectation(description: "Read only API call")
let request = EthereumRequest(method: "eth_blockNumber")
ethereum.chainId = "0x1"
mockInfuraProvider.expectation = expectation
mockReadOnlyRPCProvider.expectation = expectation
ethereum.sendRequest(request)

waitForExpectations(timeout: 2.0) { _ in
XCTAssertTrue(self.mockInfuraProvider.sendRequestCalled)
XCTAssertTrue(self.mockReadOnlyRPCProvider.sendRequestCalled)
}
}

Expand Down Expand Up @@ -150,15 +153,15 @@ class EthereumTests: XCTestCase {
waitForExpectations(timeout: 2.0)
}

func testSendRequestReadOnlyWithInfuraProvider() {
func testSendRequestReadOnlyWithReadOnlyRPCProvider() {
let expectation = self.expectation(description: "Read-only request with Infura provider")
let request = EthereumRequest(method: "eth_blockNumber")
mockInfuraProvider.expectation = expectation
mockReadOnlyRPCProvider.expectation = expectation

ethereum.sendRequest(request)

waitForExpectations(timeout: 2.0) { _ in
XCTAssertTrue(self.mockInfuraProvider.sendRequestCalled)
XCTAssertTrue(self.mockReadOnlyRPCProvider.sendRequestCalled)
}
}

Expand Down Expand Up @@ -741,9 +744,7 @@ class EthereumTests: XCTestCase {
XCTAssertFalse(mockEthereumDelegate.accountChangedCalled)
}

func testInfuraProvider() {
XCTAssertTrue(ethereum.infuraProvider is MockInfuraProvider)
ethereum.infuraProvider = nil
XCTAssertNil(ethereum.infuraProvider)
func testReadOnlyRPCProvider() {
XCTAssertTrue(ethereum.readOnlyRPCProvider is MockReadOnlyRPCProvider)
}
}
Loading

0 comments on commit dbbcba7

Please sign in to comment.