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

[ADD] Offchain Read support (EIP-3668) for eth_call and ENS resolution #208

Merged
merged 1 commit into from
May 18, 2022
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 Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import PackageDescription
let package = Package(
name: "web3.swift",
platforms: [
.iOS(SupportedPlatform.IOSVersion.v11),
.macOS(SupportedPlatform.MacOSVersion.v10_12)
.iOS(SupportedPlatform.IOSVersion.v13),
.macOS(SupportedPlatform.MacOSVersion.v11)
],
products: [
.library(name: "web3.swift", targets: ["web3"]),
Expand Down
2 changes: 1 addition & 1 deletion web3sTests/Client/EthereumClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ extension EthereumClientTests {
XCTAssertEqual(
error as? EthereumClientError,
.executionError(
.init(code: -32000, message: "execution reverted")
.init(code: -32000, message: "execution reverted", data: nil)
)
)
}
Expand Down
72 changes: 72 additions & 0 deletions web3sTests/ENS/ENSOffchainTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//
// ENSOffchainTests.swift
// web3sTests
//
// Created by Miguel on 17/05/2022.
// Copyright © 2022 Argent Labs Limited. All rights reserved.
//

import XCTest
@testable import web3

class ENSOffchainTests: XCTestCase {
var account: EthereumAccount?
var client: EthereumClient!

override func setUp() {
super.setUp()
self.client = EthereumClient(url: URL(string: TestConfig.clientUrl)!)
}

func testDNSEncode() {
XCTAssertEqual(
EthereumNameService.dnsEncode(name: "offchainexample.eth").web3.hexString,
"0x0f6f6666636861696e6578616d706c650365746800"
)
XCTAssertEqual(
EthereumNameService.dnsEncode(name: "1.offchainexample.eth").web3.hexString,
"0x01310f6f6666636861696e6578616d706c650365746800"
)

}

func testGivenRopstenRegistry_WhenResolvingOffchainENS_ResolvesCorrectly() async {
do {
let nameService = EthereumNameService(client: client!)
let ens = try await nameService.resolve(
ens: "offchainexample.eth",
mode: .allowOffchainLookup
)
XCTAssertEqual(EthereumAddress("0xd8da6bf26964af9d7eed9e03e53415d37aa96045"), ens)
} catch {
XCTFail("Expected ens but failed \(error).")
}
}

func testGivenRopstenRegistry_WhenResolvingOffchainENSAndDisabled_ThenFails() async {
do {
let nameService = EthereumNameService(client: client!)
let _ = try await nameService.resolve(
ens: "offchainexample.eth",
mode: .onchain
)
XCTFail("Expecting error")
} catch let error {
XCTAssertEqual(error as? EthereumNameServiceError, .ensUnknown)
}
}

func testGivenRopstenRegistry_WhenResolvingNonOffchainENS_ThenResolves() async {
do {
let nameService = EthereumNameService(client: client!)
let ens = try await nameService.resolve(
ens: "resolver.eth",
mode: .allowOffchainLookup
)
XCTAssertEqual(EthereumAddress("0x42d63ae25990889e35f215bc95884039ba354115"), ens)
} catch {
XCTFail("Expected ens but failed \(error).")
}
}
}

226 changes: 33 additions & 193 deletions web3sTests/ENS/ENSTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,184 +24,7 @@ class ENSTests: XCTestCase {
XCTAssertEqual(nameHash, "0x3e58ef7a2e196baf0b9d36a65cc590ac9edafb3395b7cdeb8f39206049b4534c")
}

func testGivenRopstenRegistry_WhenExistingDomainName_ResolvesOwnerAddressCorrectly() {
let expect = expectation(description: "Get the ENS owner")

do {
let function = ENSContracts.ENSRegistryFunctions.owner(contract: ENSContracts.RopstenAddress, _node: EthereumNameService.nameHash(name: "test").web3.hexData ?? Data())

let tx = try function.transaction()

client?.eth_call(tx, block: .Latest, completion: { (error, dataStr) in
guard let dataStr = dataStr else {
XCTFail()
expect.fulfill()
return
}
let owner = String(dataStr[dataStr.index(dataStr.endIndex, offsetBy: -40)...])
XCTAssertEqual(owner.web3.noHexPrefix,"09b5bd82f3351a4c8437fc6d7772a9e6cd5d25a1")
expect.fulfill()
})

} catch {
XCTFail()
expect.fulfill()
}

waitForExpectations(timeout: 20)
}

func testGivenRopstenRegistry_WhenExistingAddress_ThenResolvesCorrectly() {
let expect = expectation(description: "Get the ENS address")

let nameService = EthereumNameService(client: client!)
nameService.resolve(address: EthereumAddress("0xb0b874220ff95d62a676f58d186c832b3e6529c8"), completion: { (error, ens) in
XCTAssertEqual("julien.argent.test", ens)
expect.fulfill()
})

waitForExpectations(timeout: 20)
}

func testGivenRopstenRegistry_WhenNotExistingAddress_ThenFailsCorrectly() {
let expect = expectation(description: "Get the ENS address")

let nameService = EthereumNameService(client: client!)
nameService.resolve(address: EthereumAddress("0xb0b874220ff95d62a676f58d186c832b3e6529c9"), completion: { (error, ens) in
XCTAssertNil(ens)
XCTAssertEqual(error, .ensUnknown)
expect.fulfill()
})

waitForExpectations(timeout: 20)
}

func testGivenCustomRegistry_WhenNotExistingAddress_ThenResolvesFailsCorrectly() {
let expect = expectation(description: "Get the ENS address")

let nameService = EthereumNameService(client: client!, registryAddress: EthereumAddress("0x7D7C04B7A05539a92541105806e0971E45969F85"))
nameService.resolve(address: EthereumAddress("0xb0b874220ff95d62a676f58d186c832b3e6529c9"), completion: { (error, ens) in
XCTAssertNil(ens)
XCTAssertEqual(error, .ensUnknown)
expect.fulfill()
})

waitForExpectations(timeout: 20)
}

func testGivenRopstenRegistry_WhenExistingENS_ThenResolvesAddressCorrectly() {
let expect = expectation(description: "Get the ENS reverse lookup address")

let nameService = EthereumNameService(client: client!)
nameService.resolve(ens: "julien.argent.test", completion: { (error, ens) in
XCTAssertEqual(EthereumAddress("0xb0b874220ff95d62a676f58d186c832b3e6529c8"), ens)
expect.fulfill()
})

waitForExpectations(timeout: 20)
}

func testGivenRopstenRegistry_WhenInvalidENS_ThenErrorsRequest() {
let expect = expectation(description: "Get the ENS reverse lookup address")

let nameService = EthereumNameService(client: client!)
nameService.resolve(ens: "**somegarbage)_!!", completion: { (error, ens) in
XCTAssertNil(ens)
XCTAssertEqual(error, .ensUnknown)
expect.fulfill()
})

waitForExpectations(timeout: 20)
}

func testGivenCustomRegistry_WhenInvalidENS_ThenErrorsRequest() {
let expect = expectation(description: "Get the ENS reverse lookup address")

let nameService = EthereumNameService(client: client!, registryAddress: EthereumAddress("0x7D7C04B7A05539a92541105806e0971E45969F85"))
nameService.resolve(ens: "**somegarbage)_!!", completion: { (error, ens) in
XCTAssertNil(ens)
XCTAssertEqual(error, .ensUnknown)
expect.fulfill()
})

waitForExpectations(timeout: 20)
}

func testGivenRopstenRegistry_ThenResolvesMultipleAddressesInOneCall() {
let expect = expectation(description: "Get the ENS reverse lookup address")

let nameService = EthereumNameService(client: client!)

var results: [EthereumNameService.ResolveOutput<String>]?

nameService.resolve(addresses: [
EthereumAddress("0xb0b874220ff95d62a676f58d186c832b3e6529c8"),
EthereumAddress("0x09b5bd82f3351a4c8437fc6d7772a9e6cd5d25a1"),
EthereumAddress("0x7e691d7ffb007abe91d8a24d7f22fc74307dab06")

]) { result in
switch result {
case .success(let resolutions):
results = resolutions.map { $0.output }
case .failure:
break
}
expect.fulfill()
}

waitForExpectations(timeout: 5)

XCTAssertEqual(
results,
[
.resolved("julien.argent.test"),
.couldNotBeResolved(.ensUnknown),
.resolved("davidtests.argent.xyz")
]
)
}

func testGivenRopstenRegistry_ThenResolvesMultipleNamesInOneCall() {
let expect = expectation(description: "Get the ENS reverse lookup address")

let nameService = EthereumNameService(client: client!)

var results: [EthereumNameService.ResolveOutput<EthereumAddress>]?

nameService.resolve(names: [
"julien.argent.test",
"davidtests.argent.xyz",
"somefakeens.argent.xyz"

]) { result in
switch result {
case .success(let resolutions):
results = resolutions.map { $0.output }
case .failure:
break
}
expect.fulfill()
}

waitForExpectations(timeout: 5)

XCTAssertEqual(
results,
[
.resolved(EthereumAddress("0xb0b874220ff95d62a676f58d186c832b3e6529c8")),
.resolved(EthereumAddress("0x7e691d7ffb007abe91d8a24d7f22fc74307dab06")),
.couldNotBeResolved(.ensUnknown)
]
)
}
}


#if compiler(>=5.5) && canImport(_Concurrency)

@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
extension ENSTests {
func testGivenRopstenRegistry_WhenExistingDomainName_ResolvesOwnerAddressCorrectly_Async() async {
func testGivenRopstenRegistry_WhenExistingDomainName_ResolvesOwnerAddressCorrectly() async {
Comment on lines -200 to +27
Copy link
Member Author

Choose a reason for hiding this comment

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

Default tests now using async/await

do {
let function = ENSContracts.ENSRegistryFunctions.owner(contract: ENSContracts.RopstenAddress, _node: EthereumNameService.nameHash(name: "test").web3.hexData ?? Data())

Expand All @@ -220,67 +43,85 @@ extension ENSTests {
}
}

func testGivenRopstenRegistry_WhenExistingAddress_ThenResolvesCorrectly_Async() async {
func testGivenRopstenRegistry_WhenExistingAddress_ThenResolvesCorrectly() async {
do {
let nameService = EthereumNameService(client: client!)
let ens = try await nameService.resolve(address: EthereumAddress("0xb0b874220ff95d62a676f58d186c832b3e6529c8"))
let ens = try await nameService.resolve(
address: EthereumAddress("0xb0b874220ff95d62a676f58d186c832b3e6529c8"),
mode: .onchain
)
XCTAssertEqual("julien.argent.test", ens)
} catch {
XCTFail("Expected ens but failed \(error).")
}
}

func testGivenRopstenRegistry_WhenNotExistingAddress_ThenFailsCorrectly_Async() async {
func testGivenRopstenRegistry_WhenNotExistingAddress_ThenFailsCorrectly() async {
do {
let nameService = EthereumNameService(client: client!)
_ = try await nameService.resolve(address: EthereumAddress("0xb0b874220ff95d62a676f58d186c832b3e6529c9"))
_ = try await nameService.resolve(
address: EthereumAddress("0xb0b874220ff95d62a676f58d186c832b3e6529c9"),
mode: .onchain
)
XCTFail("Expected to throw while awaiting, but succeeded")
} catch {
XCTAssertEqual(error as? EthereumNameServiceError, .ensUnknown)
}
}

func testGivenCustomRegistry_WhenNotExistingAddress_ThenResolvesFailsCorrectly_Async() async {
func testGivenCustomRegistry_WhenNotExistingAddress_ThenResolvesFailsCorrectly() async {
do {
let nameService = EthereumNameService(client: client!, registryAddress: EthereumAddress("0x7D7C04B7A05539a92541105806e0971E45969F85"))
_ = try await nameService.resolve(address: EthereumAddress("0xb0b874220ff95d62a676f58d186c832b3e6529c9"))
_ = try await nameService.resolve(
address: EthereumAddress("0xb0b874220ff95d62a676f58d186c832b3e6529c9"),
mode: .onchain
)
XCTFail("Expected to throw while awaiting, but succeeded")
} catch {
XCTAssertEqual(error as? EthereumNameServiceError, .ensUnknown)
}
}

func testGivenRopstenRegistry_WhenExistingENS_ThenResolvesAddressCorrectly_Async() async {
func testGivenRopstenRegistry_WhenExistingENS_ThenResolvesAddressCorrectly() async {
do {
let nameService = EthereumNameService(client: client!)
let ens = try await nameService.resolve(ens: "julien.argent.test")
let ens = try await nameService.resolve(
ens: "julien.argent.test",
mode: .onchain
)
XCTAssertEqual(EthereumAddress("0xb0b874220ff95d62a676f58d186c832b3e6529c8"), ens)
} catch {
XCTFail("Expected ens but failed \(error).")
}
}

func testGivenRopstenRegistry_WhenInvalidENS_ThenErrorsRequest_Async() async {
func testGivenRopstenRegistry_WhenInvalidENS_ThenErrorsRequest() async {
do {
let nameService = EthereumNameService(client: client!)
_ = try await nameService.resolve(ens: "**somegarbage)_!!")
_ = try await nameService.resolve(
ens: "**somegarbage)_!!",
mode: .onchain
)
XCTFail("Expected to throw while awaiting, but succeeded")
} catch {
XCTAssertEqual(error as? EthereumNameServiceError, .ensUnknown)
}
}

func testGivenCustomRegistry_WhenInvalidENS_ThenErrorsRequest_Async() async {
func testGivenCustomRegistry_WhenInvalidENS_ThenErrorsRequest() async {
do {
let nameService = EthereumNameService(client: client!, registryAddress: EthereumAddress("0x7D7C04B7A05539a92541105806e0971E45969F85"))
_ = try await nameService.resolve(ens: "**somegarbage)_!!")
_ = try await nameService.resolve(
ens: "**somegarbage)_!!",
mode: .onchain
)
XCTFail("Expected to throw while awaiting, but succeeded")
} catch {
XCTAssertEqual(error as? EthereumNameServiceError, .ensUnknown)
}
}

func testGivenRopstenRegistry_ThenResolvesMultipleAddressesInOneCall_Async() async {
func testGivenRopstenRegistry_ThenResolvesMultipleAddressesInOneCall() async {
let nameService = EthereumNameService(client: client!)

var results: [EthereumNameService.ResolveOutput<String>]?
Expand Down Expand Up @@ -308,7 +149,7 @@ extension ENSTests {
)
}

func testGivenRopstenRegistry_ThenResolvesMultipleNamesInOneCall_Async() async {
func testGivenRopstenRegistry_ThenResolvesMultipleNamesInOneCall() async {
let nameService = EthereumNameService(client: client!)

var results: [EthereumNameService.ResolveOutput<EthereumAddress>]?
Expand Down Expand Up @@ -337,4 +178,3 @@ extension ENSTests {
}
}

#endif
Loading