diff --git a/Gemfile b/Gemfile index f326c84a..d40b3e89 100644 --- a/Gemfile +++ b/Gemfile @@ -2,4 +2,4 @@ source "https://rubygems.org" #iOS -gem 'cocoapods' +gem 'cocoapods', '1.5.3' diff --git a/Gemfile.lock b/Gemfile.lock index 5d75afb7..5be50c58 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,12 +2,12 @@ GEM remote: https://rubygems.org/ specs: CFPropertyList (3.0.0) - activesupport (4.2.10) + activesupport (4.2.11.1) i18n (~> 0.7) minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - atomos (0.1.2) + atomos (0.1.3) claide (1.0.2) cocoapods (1.5.3) activesupport (>= 4.0.2, < 5) @@ -32,18 +32,18 @@ GEM activesupport (>= 4.0.2, < 6) fuzzy_match (~> 2.0.4) nap (~> 1.0) - cocoapods-deintegrate (1.0.2) - cocoapods-downloader (1.2.1) + cocoapods-deintegrate (1.0.4) + cocoapods-downloader (1.2.2) cocoapods-plugins (1.0.0) nap cocoapods-search (1.0.0) - cocoapods-stats (1.0.0) - cocoapods-trunk (1.3.0) + cocoapods-stats (1.1.0) + cocoapods-trunk (1.3.1) nap (>= 0.8, < 2.0) netrc (~> 0.11) cocoapods-try (1.1.0) colored2 (3.1.2) - concurrent-ruby (1.0.5) + concurrent-ruby (1.1.5) escape (0.0.4) fourflusher (2.0.1) fuzzy_match (2.0.4) @@ -51,26 +51,26 @@ GEM i18n (0.9.5) concurrent-ruby (~> 1.0) minitest (5.11.3) - molinillo (0.6.5) - nanaimo (0.2.5) + molinillo (0.6.6) + nanaimo (0.2.6) nap (1.1.0) netrc (0.11.0) - ruby-macho (1.2.0) + ruby-macho (1.4.0) thread_safe (0.3.6) tzinfo (1.2.5) thread_safe (~> 0.1) - xcodeproj (1.5.9) + xcodeproj (1.8.2) CFPropertyList (>= 2.3.3, < 4.0) - atomos (~> 0.1.2) + atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) - nanaimo (~> 0.2.5) + nanaimo (~> 0.2.6) PLATFORMS ruby DEPENDENCIES - cocoapods + cocoapods (= 1.5.3) BUNDLED WITH - 1.16.1 + 1.17.3 diff --git a/Podfile b/Podfile index 99a85e2b..6273c172 100644 --- a/Podfile +++ b/Podfile @@ -1,5 +1,5 @@ def all_pods - pod 'BigInt', '~> 3.0.1' + pod 'BigInt', '3.1.0' end target 'web3swift' do diff --git a/Podfile.lock b/Podfile.lock index 1ea84676..c66611f8 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,10 +1,10 @@ PODS: - - BigInt (3.0.1): + - BigInt (3.1.0): - SipHash (~> 1.2) - - SipHash (1.2.0) + - SipHash (1.2.2) DEPENDENCIES: - - BigInt (~> 3.0.1) + - BigInt (= 3.1.0) SPEC REPOS: https://github.com/cocoapods/specs.git: @@ -12,9 +12,9 @@ SPEC REPOS: - SipHash SPEC CHECKSUMS: - BigInt: 8e8a52161c745cd3ab78e3dc346a9fbee51e6cf6 - SipHash: c6e9e43e9c531b5bc6602545130c26194a6d31ce + BigInt: 76b5dfdfa3e2e478d4ffdf161aeede5502e2742f + SipHash: fad90a4683e420c52ef28063063dbbce248ea6d4 -PODFILE CHECKSUM: 67f19944c0b15799d71ad44aab63ca30fcbd5189 +PODFILE CHECKSUM: 7d6817b2b66ca961a4ac6f21b073018916aa7067 -COCOAPODS: 1.5.2 +COCOAPODS: 1.5.3 diff --git a/web3.swift.podspec b/web3.swift.podspec index b89996f6..4917b322 100644 --- a/web3.swift.podspec +++ b/web3.swift.podspec @@ -1,27 +1,27 @@ Pod::Spec.new do |s| s.name = 'web3.swift' - s.version = '0.0.5' + s.version = '0.1.0' s.license = 'MIT' s.summary = 'Ethereum API for Swift' s.homepage = 'https://github.com/argentlabs/web3.swift' - s.authors = { 'Julien Niset' => 'julien@argent.im', 'Matt Marshall' => 'matt@argent.im' } + s.authors = { 'Julien Niset' => 'julien@argent.xyz', 'Matt Marshall' => 'matt@argent.xyz', 'Miguel Angel Quiñones' => 'miguel@argent.xyz' } s.source = { :git => 'https://github.com/argentlabs/web3.swift.git', :tag => s.version.to_s } s.module_name = 'web3' - s.swift_version = '4.1' + s.swift_version = '4.2' s.ios.deployment_target = '9.0' s.source_files = 'web3swift/web3swift.h', 'web3swift/src/**/*.swift', 'web3swift/lib/**/*.{c,h}' s.pod_target_xcconfig = { - 'SWIFT_INCLUDE_PATHS[sdk=iphonesimulator*]' => '$(PODS_TARGET_SRCROOT)/web3swift/lib/** $(PODS_TARGET_SRCROOT)/web3swift/frameworks/CommonCrypto/iphonesimulator/', - 'SWIFT_INCLUDE_PATHS[sdk=iphoneos*]' => '$(PODS_TARGET_SRCROOT)/web3swift/lib/** $(PODS_TARGET_SRCROOT)/web3swift/frameworks/CommonCrypto/iphoneos/' + 'SWIFT_INCLUDE_PATHS[sdk=iphonesimulator*]' => '$(PODS_TARGET_SRCROOT)/web3swift/lib/**', + 'SWIFT_INCLUDE_PATHS[sdk=iphoneos*]' => '$(PODS_TARGET_SRCROOT)/web3swift/lib/**' } - s.preserve_paths = 'web3swift/lib/**/module.map', 'web3swift/frameworks/CommonCrypto/**/*' + s.preserve_paths = 'web3swift/lib/**/module.map' # Do not include the C libs in export s.public_header_files = 'web3swift/web3swift.h' - s.dependency 'BigInt', '~> 3.0.1' + s.dependency 'BigInt', '~> 3.1.0' end diff --git a/web3sTests/Contract/ABIDecoderTests.swift b/web3sTests/Contract/ABIDecoderTests.swift index 1bc97b63..1ad8f3fd 100644 --- a/web3sTests/Contract/ABIDecoderTests.swift +++ b/web3sTests/Contract/ABIDecoderTests.swift @@ -105,4 +105,26 @@ class ABIDecoderTests: XCTestCase { XCTFail() } } + + func testDecodeEmptyDynamicData() { + do { + let decoded = try ABIDecoder.decodeData("0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", types: [.DynamicBytes]) as! [String] + XCTAssertEqual(decoded.first, "") + } catch let error { + print(error.localizedDescription) + XCTFail() + } + } + + func testDecodeDynamicData() { + do { + let decoded = try ABIDecoder.decodeData("0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000", types: [.DynamicBytes]) as! [String] + + XCTAssertEqual(decoded.first, "0x48656c6c6f2c20776f726c6421") + } catch let error { + print(error.localizedDescription) + XCTFail() + } + } + } diff --git a/web3sTests/Contract/ABIFunctionEncoderTests.swift b/web3sTests/Contract/ABIFunctionEncoderTests.swift new file mode 100644 index 00000000..d385649a --- /dev/null +++ b/web3sTests/Contract/ABIFunctionEncoderTests.swift @@ -0,0 +1,44 @@ +// +// ABIFunctionEncoderTests.swift +// web3swift +// +// Created by Miguel on 28/11/2018. +// Copyright © 2018 Argent Labs Limited. All rights reserved. +// + +import XCTest +import BigInt +@testable import web3swift + +class ABIFuncionEncoderTests: XCTestCase { + var encoder: ABIFunctionEncoder! + + override func setUp() { + encoder = ABIFunctionEncoder("test") + + } + + func testGivenEmptyString_ThenEncodesCorrectly() { + try! encoder.encode("") + let encoded = try! encoder.encoded() + XCTAssertEqual(String(hexFromBytes: encoded.bytes), "0xf9fbd554000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") + } + + func testGivenNonEmptyString_ThenEncodesCorrectly() { + try! encoder.encode("hi") + let encoded = try! encoder.encoded() + XCTAssertEqual(String(hexFromBytes: encoded.bytes), "0xf9fbd554000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000026869000000000000000000000000000000000000000000000000000000000000") + } + + func testGivenEmptyData_ThenEncodesCorrectly() { + try! encoder.encode(Data()) + let encoded = try! encoder.encoded() + XCTAssertEqual(String(hexFromBytes: encoded.bytes), "0x2f570a2300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000") + } + + func testGivenNonEmptyData_ThenEncodesCorrectly() { + try! encoder.encode(Data(bytes: "hi".bytes)) + let encoded = try! encoder.encoded() + XCTAssertEqual(String(hexFromBytes: encoded.bytes), "0x2f570a23000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000026869000000000000000000000000000000000000000000000000000000000000") + } +} diff --git a/web3sTests/ENS/ENSTests.swift b/web3sTests/ENS/ENSTests.swift index 9d8e171b..340dcd4b 100644 --- a/web3sTests/ENS/ENSTests.swift +++ b/web3sTests/ENS/ENSTests.swift @@ -18,21 +18,17 @@ class ENSTests: XCTestCase { self.client = EthereumClient(url: URL(string: TestConfig.clientUrl)!) } - override func tearDown() { - super.tearDown() - } - - func testNameHash() { + func testGivenName_ThenResolvesNameHash() { let name = "argent.test" let nameHash = EthereumNameService.nameHash(name: name) XCTAssertEqual(nameHash, "0x3e58ef7a2e196baf0b9d36a65cc590ac9edafb3395b7cdeb8f39206049b4534c") } - func testOwner() { + func testGivenRopstenRegistry_WhenExistingDomainName_ResolvesOwnerAddressCorrectly() { let expect = expectation(description: "Get the ENS owner") do { - let contract = ENSRegistryContract(chainId: EthereumNetwork.Ropsten.intValue) + let contract = ENSRegistryContract(chainId: EthereumNetwork.Ropsten.intValue, registryAddress: nil) let tx = try contract?.owner(name: "test") client?.eth_call(tx!, block: .Latest, completion: { (error, dataStr) in @@ -49,7 +45,7 @@ class ENSTests: XCTestCase { waitForExpectations(timeout: 20) } - func testResolveAddress() { + func testGivenRopstenRegistry_WhenExistingAddress_ThenResolvesCorrectly() { let expect = expectation(description: "Get the ENS address") let nameService = EthereumNameService(client: client!) @@ -61,7 +57,33 @@ class ENSTests: XCTestCase { waitForExpectations(timeout: 20) } - func testResolveAlias() { + 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!) @@ -73,4 +95,30 @@ class ENSTests: XCTestCase { 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) + } + } diff --git a/web3swift.xcodeproj/project.pbxproj b/web3swift.xcodeproj/project.pbxproj index c0f88e6e..312448c4 100644 --- a/web3swift.xcodeproj/project.pbxproj +++ b/web3swift.xcodeproj/project.pbxproj @@ -61,6 +61,7 @@ 3CF37CF7203744400030520E /* KeystoreUtilTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CF37CF6203744400030520E /* KeystoreUtilTests.swift */; }; 473D9B8A20F629C500FD04BB /* TransactionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 473D9B8820F6297D00FD04BB /* TransactionTests.swift */; }; 473E682F20CE7F80006D11AF /* EthereumBlockInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 473E682E20CE7F80006D11AF /* EthereumBlockInfo.swift */; }; + 47ADCD9221AE9CA3006DE71F /* ABIFunctionEncoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47ADCD9021AE9B8E006DE71F /* ABIFunctionEncoderTests.swift */; }; 6C4ABDDAA3313A1B32EAB620 /* Pods_web3swiftTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E4FAB97C27DB6CBB355E0F1 /* Pods_web3swiftTests.framework */; }; 9164E8EEDA7FB33A6638D561 /* Pods_web3swift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD54E6F686FEE6C1126AB6A0 /* Pods_web3swift.framework */; }; C91A7E80205C1F120074D3B4 /* ABIEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C91A7E7F205C1F120074D3B4 /* ABIEncoder.swift */; }; @@ -187,13 +188,12 @@ 3CF37CE02037096A0030520E /* AesUtilTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AesUtilTests.swift; sourceTree = ""; }; 3CF37CE2203720F30030520E /* KeyDerivation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyDerivation.swift; sourceTree = ""; }; 3CF37CEA20372CA10030520E /* KeyDerivationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyDerivationTests.swift; sourceTree = ""; }; - 3CF37CEF20372FF70030520E /* module.map */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.map; sourceTree = ""; }; - 3CF37CF120372FF70030520E /* module.map */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.map; sourceTree = ""; }; 3CF37CF420373E320030520E /* Data+RandomTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+RandomTests.swift"; sourceTree = ""; }; 3CF37CF6203744400030520E /* KeystoreUtilTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeystoreUtilTests.swift; sourceTree = ""; }; 45FF08D408285DBA7FF4564A /* Pods-web3sTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-web3sTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-web3sTests/Pods-web3sTests.release.xcconfig"; sourceTree = ""; }; 473D9B8820F6297D00FD04BB /* TransactionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionTests.swift; sourceTree = ""; }; 473E682E20CE7F80006D11AF /* EthereumBlockInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthereumBlockInfo.swift; sourceTree = ""; }; + 47ADCD9021AE9B8E006DE71F /* ABIFunctionEncoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ABIFunctionEncoderTests.swift; sourceTree = ""; }; 52B3D38DF87EAFCBBD99CCF1 /* Pods-web3swiftTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-web3swiftTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-web3swiftTests/Pods-web3swiftTests.debug.xcconfig"; sourceTree = ""; }; 595F7375549A81C8950C1F8E /* Pods-web3s.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-web3s.release.xcconfig"; path = "Pods/Target Support Files/Pods-web3s/Pods-web3s.release.xcconfig"; sourceTree = ""; }; 5E4FAB97C27DB6CBB355E0F1 /* Pods_web3swiftTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_web3swiftTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -338,7 +338,6 @@ 3CF37C2F203437D70030520E /* web3swift.h */, 3CF37C6120343BDD0030520E /* src */, 3CF37C46203438590030520E /* lib */, - 3CF37CEC20372FF70030520E /* frameworks */, 3CF37C30203437D70030520E /* Info.plist */, ); path = web3swift; @@ -502,39 +501,6 @@ path = aes; sourceTree = ""; }; - 3CF37CEC20372FF70030520E /* frameworks */ = { - isa = PBXGroup; - children = ( - 3CF37CED20372FF70030520E /* CommonCrypto */, - ); - path = frameworks; - sourceTree = ""; - }; - 3CF37CED20372FF70030520E /* CommonCrypto */ = { - isa = PBXGroup; - children = ( - 3CF37CEE20372FF70030520E /* iphoneos */, - 3CF37CF020372FF70030520E /* iphonesimulator */, - ); - path = CommonCrypto; - sourceTree = ""; - }; - 3CF37CEE20372FF70030520E /* iphoneos */ = { - isa = PBXGroup; - children = ( - 3CF37CEF20372FF70030520E /* module.map */, - ); - path = iphoneos; - sourceTree = ""; - }; - 3CF37CF020372FF70030520E /* iphonesimulator */ = { - isa = PBXGroup; - children = ( - 3CF37CF120372FF70030520E /* module.map */, - ); - path = iphonesimulator; - sourceTree = ""; - }; 473D9B8720F6296900FD04BB /* Transaction */ = { isa = PBXGroup; children = ( @@ -593,6 +559,7 @@ 3C1C133C203D71110052986A /* EthereumContractTests.swift */, C9A78E502058498800CF8316 /* ABIEncoderTests.swift */, C91A7E87206120EA0074D3B4 /* ABIDecoderTests.swift */, + 47ADCD9021AE9B8E006DE71F /* ABIFunctionEncoderTests.swift */, ); path = Contract; sourceTree = ""; @@ -991,6 +958,7 @@ C9A78E6D2059406A00CF8316 /* ByteExtensionsTests.swift in Sources */, 3CF37CF7203744400030520E /* KeystoreUtilTests.swift in Sources */, 473D9B8A20F629C500FD04BB /* TransactionTests.swift in Sources */, + 47ADCD9221AE9CA3006DE71F /* ABIFunctionEncoderTests.swift in Sources */, C9A78E652058787300CF8316 /* ENSTests.swift in Sources */, C91A7E8E206144CC0074D3B4 /* TestConfig.swift in Sources */, ); @@ -1144,11 +1112,11 @@ PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; SWIFT_INCLUDE_PATHS = "$(SRCROOT)/web3swift/lib/**"; - "SWIFT_INCLUDE_PATHS[sdk=iphoneos*]" = "$(SRCROOT)/web3swift/lib/** $(SRCROOT)/web3swift/frameworks/CommonCrypto/iphoneos"; - "SWIFT_INCLUDE_PATHS[sdk=iphonesimulator*]" = "$(SRCROOT)/web3swift/lib/** $(SRCROOT)/web3swift/frameworks/CommonCrypto/iphonesimulator"; + "SWIFT_INCLUDE_PATHS[sdk=iphoneos*]" = "$(SRCROOT)/web3swift/lib/**"; + "SWIFT_INCLUDE_PATHS[sdk=iphonesimulator*]" = "$(SRCROOT)/web3swift/lib/**"; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -1173,10 +1141,10 @@ PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; SWIFT_INCLUDE_PATHS = "$(SRCROOT)/web3swift/lib/**"; - "SWIFT_INCLUDE_PATHS[sdk=iphoneos*]" = "$(SRCROOT)/web3swift/lib/** $(SRCROOT)/web3swift/frameworks/CommonCrypto/iphoneos/**"; - "SWIFT_INCLUDE_PATHS[sdk=iphonesimulator*]" = "$(SRCROOT)/web3swift/lib/** $(SRCROOT)/web3swift/frameworks/CommonCrypto/iphonesimulator"; + "SWIFT_INCLUDE_PATHS[sdk=iphoneos*]" = "$(SRCROOT)/web3swift/lib/**"; + "SWIFT_INCLUDE_PATHS[sdk=iphonesimulator*]" = "$(SRCROOT)/web3swift/lib/**"; SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/web3swift/frameworks/CommonCrypto/iphoneos/module.map b/web3swift/frameworks/CommonCrypto/iphoneos/module.map deleted file mode 100644 index 125b7720..00000000 --- a/web3swift/frameworks/CommonCrypto/iphoneos/module.map +++ /dev/null @@ -1,4 +0,0 @@ -module CommonCrypto [system] { - header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/CommonCrypto/CommonCrypto.h" - export * -} diff --git a/web3swift/frameworks/CommonCrypto/iphonesimulator/module.map b/web3swift/frameworks/CommonCrypto/iphonesimulator/module.map deleted file mode 100644 index 835d6863..00000000 --- a/web3swift/frameworks/CommonCrypto/iphonesimulator/module.map +++ /dev/null @@ -1,4 +0,0 @@ -module CommonCrypto [system] { - header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/CommonCrypto/CommonCrypto.h" - export * -} diff --git a/web3swift/src/Client/JSONRPC.swift b/web3swift/src/Client/JSONRPC.swift index 2c52395d..396cce16 100644 --- a/web3swift/src/Client/JSONRPC.swift +++ b/web3swift/src/Client/JSONRPC.swift @@ -52,7 +52,7 @@ public class EthereumRPC { return } - var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 5.0) + var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData) request.httpMethod = "POST" request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.addValue("application/json", forHTTPHeaderField: "Accept") diff --git a/web3swift/src/Client/Models/EthereumAddress.swift b/web3swift/src/Client/Models/EthereumAddress.swift index 5bf0fc1e..f9200fdf 100644 --- a/web3swift/src/Client/Models/EthereumAddress.swift +++ b/web3swift/src/Client/Models/EthereumAddress.swift @@ -8,7 +8,7 @@ import Foundation -public struct EthereumAddress: Codable { +public struct EthereumAddress: Codable, Hashable { public let value: String public static let zero = EthereumAddress("0x0000000000000000000000000000000000000000") @@ -25,11 +25,9 @@ public struct EthereumAddress: Codable { var container = encoder.singleValueContainer() try container.encode(self.value) } -} -extension EthereumAddress: Hashable { - public var hashValue: Int { - return self.value.hashValue + public func hash(into hasher: inout Hasher) { + hasher.combine(self.value.lowercased()) } public static func == (lhs: EthereumAddress, rhs: EthereumAddress) -> Bool { diff --git a/web3swift/src/Contract/ABIDecoder.swift b/web3swift/src/Contract/ABIDecoder.swift index 5ec1c4d4..6bc420b0 100644 --- a/web3swift/src/Contract/ABIDecoder.swift +++ b/web3swift/src/Contract/ABIDecoder.swift @@ -42,6 +42,9 @@ public class ABIDecoder { throw ABIError.invalidValue } let size = Int(bint) + guard size > 0 else { + return "" + } let lowerRange = newOffset + 32 let upperRange = newOffset + 32 + size - 1 guard lowerRange <= upperRange else { throw ABIError.invalidValue } diff --git a/web3swift/src/Contract/ABIEncoder.swift b/web3swift/src/Contract/ABIEncoder.swift index 42f2d964..5538c621 100644 --- a/web3swift/src/Contract/ABIEncoder.swift +++ b/web3swift/src/Contract/ABIEncoder.swift @@ -53,7 +53,13 @@ public class ABIEncoder { // Bytes are hex encoded guard let bytes = value.bytesFromHex else { throw ABIError.invalidValue } let len = try encode(String(bytes.count), forType: ABIRawType.FixedUInt(256)) - let pack = (bytes.count - (bytes.count % 32)) / 32 + 1 + let pack: Int + if bytes.count == 0 { + pack = 0 + } else { + pack = (bytes.count - (bytes.count % 32)) / 32 + 1 + } + encoded = len + bytes + [UInt8](repeating: 0x00, count: pack * 32 - bytes.count) case .FixedBytes(_): // Bytes are hex encoded diff --git a/web3swift/src/Contract/Statically Typed/ABIDecoder+Static.swift b/web3swift/src/Contract/Statically Typed/ABIDecoder+Static.swift index 210465b6..059e26a0 100644 --- a/web3swift/src/Contract/Statically Typed/ABIDecoder+Static.swift +++ b/web3swift/src/Contract/Statically Typed/ABIDecoder+Static.swift @@ -24,8 +24,16 @@ extension ABIDecoder { } public static func decode(_ data: String, to: EthereumAddress.Type) throws -> EthereumAddress { + // If from log value, already decoded during initial log decode process + if data.count == EthereumAddress.zero.value.count { + return EthereumAddress(data) + } + guard let bytes = data.bytesFromHex else { throw ABIError.invalidValue } - guard let decodedData = try ABIDecoder.decode(bytes, forType: ABIRawType.FixedAddress, offset: 0) as? String else { throw ABIError.invalidValue } + + guard let decodedData = try ABIDecoder.decode(bytes, forType: ABIRawType.FixedAddress, offset: 0) as? String else { + throw ABIError.invalidValue + } return EthereumAddress(decodedData) } @@ -68,4 +76,5 @@ extension ABIDecoder { guard let data = Data(hex: data) else { throw ABIError.invalidValue } return data } + } diff --git a/web3swift/src/Contract/Statically Typed/ABIEvent.swift b/web3swift/src/Contract/Statically Typed/ABIEvent.swift index 64e8898b..e9f6c766 100644 --- a/web3swift/src/Contract/Statically Typed/ABIEvent.swift +++ b/web3swift/src/Contract/Statically Typed/ABIEvent.swift @@ -13,7 +13,7 @@ public protocol ABIEvent { static var types: [ABIType.Type] { get } static var typesIndexed: [Bool] { get } var log: EthereumLog { get } - init?(topics: [String], data: [ABIType], log: EthereumLog) throws + init?(topics: [String], data: [String], log: EthereumLog) throws static func checkParameters(_ topics: [String], _ data: [ABIType]) throws static func signature() throws -> String diff --git a/web3swift/src/Contract/Statically Typed/ABIFunction.swift b/web3swift/src/Contract/Statically Typed/ABIFunction.swift index 6e1e7edc..3ae14992 100644 --- a/web3swift/src/Contract/Statically Typed/ABIFunction.swift +++ b/web3swift/src/Contract/Statically Typed/ABIFunction.swift @@ -25,7 +25,7 @@ public protocol ABIResponse { } public extension ABIResponse { - public init?(data: String) throws { + init?(data: String) throws { guard let decodedData = try ABIDecoder.decodeData(data, types: Self.types) as? [String] else { // Response is not an array of Strings - likely array of array of Strings throw ABIError.invalidType diff --git a/web3swift/src/Contract/Statically Typed/ABIFunctionEncoder.swift b/web3swift/src/Contract/Statically Typed/ABIFunctionEncoder.swift index a3410081..9a339f4d 100644 --- a/web3swift/src/Contract/Statically Typed/ABIFunctionEncoder.swift +++ b/web3swift/src/Contract/Statically Typed/ABIFunctionEncoder.swift @@ -59,9 +59,9 @@ public class ABIFunctionEncoder { private func encode(type: ABIRawType, value: String) throws { let result = try ABIEncoder.encode(value, forType: type) - + if type.isDynamic { - let pos = self.types.count*32 + tail.count + let pos = 32 + self.types.count*32 + tail.count head += try ABIEncoder.encode(String(pos), forType: ABIRawType.FixedInt(256)) tail += result } else { diff --git a/web3swift/src/Contract/Statically Typed/EthereumClient+Static.swift b/web3swift/src/Contract/Statically Typed/EthereumClient+Static.swift index 3fc524f5..6cd280d3 100644 --- a/web3swift/src/Contract/Statically Typed/EthereumClient+Static.swift +++ b/web3swift/src/Contract/Statically Typed/EthereumClient+Static.swift @@ -9,7 +9,7 @@ import Foundation public extension ABIFunction { - public func execute(withClient client: EthereumClient, account: EthereumAccount, completion: @escaping((EthereumClientError?, String?) -> Void)) { + func execute(withClient client: EthereumClient, account: EthereumAccount, completion: @escaping((EthereumClientError?, String?) -> Void)) { guard let tx = try? self.transaction() else { return completion(EthereumClientError.encodeIssue, nil) @@ -26,7 +26,7 @@ public extension ABIFunction { } - public func call(withClient client: EthereumClient, responseType: T.Type, completion: @escaping((EthereumClientError?, T?) -> Void)) { + func call(withClient client: EthereumClient, responseType: T.Type, completion: @escaping((EthereumClientError?, T?) -> Void)) { guard let tx = try? self.transaction() else { return completion(EthereumClientError.encodeIssue, nil) @@ -47,7 +47,7 @@ public extension ABIFunction { } public extension EthereumClient { - public func getEvents(addresses: [String]?, topics: [String?]?, fromBlock: EthereumBlock, toBlock: EthereumBlock, eventTypes: [ABIEvent.Type], completion: @escaping((EthereumClientError?, [ABIEvent], [EthereumLog]) -> Void)) { + func getEvents(addresses: [String]?, topics: [String?]?, fromBlock: EthereumBlock, toBlock: EthereumBlock, eventTypes: [ABIEvent.Type], completion: @escaping((EthereumClientError?, [ABIEvent], [EthereumLog]) -> Void)) { self.eth_getLogs(addresses: addresses, topics: topics, fromBlock: fromBlock, toBlock: toBlock) { (error, logs) in @@ -75,8 +75,19 @@ public extension EthereumClient { } let dataTypes = eventType.types.enumerated().filter { eventType.typesIndexed[$0.offset] == false }.compactMap { $0.element } - - guard let decoded = try? ABIDecoder.decodeData(log.data, types: dataTypes), let eventOpt = try? eventType.init(topics: Array(log.topics.dropFirst()), data: decoded, log: log), let event = eventOpt else { + + guard let decoded = try? ABIDecoder.decodeData(log.data, types: dataTypes) else { + unprocessed.append(log) + continue + } + + let strs = decoded.compactMap { $0 as? String } + guard strs.count == decoded.count else { + unprocessed.append(log) + continue + } + + guard let eventOpt = try? eventType.init(topics: Array(log.topics.dropFirst()), data: strs, log: log), let event = eventOpt else { unprocessed.append(log) continue } diff --git a/web3swift/src/ENS/ENSRegistryContract.swift b/web3swift/src/ENS/ENSRegistryContract.swift index c08e6b4b..8d796dd6 100644 --- a/web3swift/src/ENS/ENSRegistryContract.swift +++ b/web3swift/src/ENS/ENSRegistryContract.swift @@ -11,18 +11,23 @@ import Foundation class ENSRegistryContract: EthereumJSONContract { private var chainId: Int - init?(chainId: Int) { + init?(chainId: Int, registryAddress: EthereumAddress?) { self.chainId = chainId let network = EthereumNetwork.fromString(String(chainId)) + let address: EthereumAddress - switch network { - case .Ropsten: - address = ENSContracts.RopstenAddress - case .Mainnet: - address = ENSContracts.MainnetAddress - default: - return nil + if let registryAddress = registryAddress { + address = registryAddress + } else { + switch network { + case .Ropsten: + address = ENSContracts.RopstenAddress + case .Mainnet: + address = ENSContracts.MainnetAddress + default: + return nil + } } let json = ENSContracts.RegistryJson diff --git a/web3swift/src/ENS/EthereumNameService.swift b/web3swift/src/ENS/EthereumNameService.swift index 081b1328..68227f1b 100644 --- a/web3swift/src/ENS/EthereumNameService.swift +++ b/web3swift/src/ENS/EthereumNameService.swift @@ -9,12 +9,12 @@ import Foundation protocol EthereumNameServiceProtocol { - init(client: EthereumClientProtocol) + init(client: EthereumClientProtocol, registryAddress: EthereumAddress?) func resolve(address: EthereumAddress, completion: @escaping((EthereumNameServiceError?, String?) -> Void)) -> Void func resolve(ens: String, completion: @escaping((EthereumNameServiceError?, String?) -> Void)) -> Void } -public enum EthereumNameServiceError: Error { +public enum EthereumNameServiceError: Error, Equatable { case noNetwork case noResolver case ensUnknown @@ -25,9 +25,11 @@ public enum EthereumNameServiceError: Error { // This is an example of interacting via a JSON Definition contract API public class EthereumNameService: EthereumNameServiceProtocol { let client: EthereumClientProtocol + let registryAddress: EthereumAddress? - required public init(client: EthereumClientProtocol) { + required public init(client: EthereumClientProtocol, registryAddress: EthereumAddress? = nil) { self.client = client + self.registryAddress = registryAddress } public func resolve(address: EthereumAddress, completion: @escaping ((EthereumNameServiceError?, String?) -> Void)) { @@ -36,7 +38,7 @@ public class EthereumNameService: EthereumNameServiceProtocol { } let ensReverse = address.value.noHexPrefix + ".addr.reverse" - guard let regContract = ENSRegistryContract(chainId: network.intValue), let registryTransaction = try? regContract.resolver(name: ensReverse) else { + guard let regContract = ENSRegistryContract(chainId: network.intValue, registryAddress: registryAddress), let registryTransaction = try? regContract.resolver(name: ensReverse) else { return completion(EthereumNameServiceError.contractIssue, nil) } @@ -45,6 +47,10 @@ public class EthereumNameService: EthereumNameServiceProtocol { return completion(EthereumNameServiceError.noResolver, nil) } + guard resolverData != "0x" else { + return completion(EthereumNameServiceError.ensUnknown, nil) + } + let idx = resolverData.index(resolverData.endIndex, offsetBy: -40) let resolverAddress = EthereumAddress(String(resolverData[idx...]).withHexPrefix) let nameHash = EthereumNameService.nameHash(name: ensReverse) @@ -73,7 +79,7 @@ public class EthereumNameService: EthereumNameServiceProtocol { return completion(EthereumNameServiceError.noNetwork, nil) } - guard let regContract = ENSRegistryContract(chainId: network.intValue), let registryTransaction = try? regContract.resolver(name: ens) else { + guard let regContract = ENSRegistryContract(chainId: network.intValue, registryAddress: registryAddress), let registryTransaction = try? regContract.resolver(name: ens) else { return completion(EthereumNameServiceError.contractIssue, nil) } @@ -82,6 +88,10 @@ public class EthereumNameService: EthereumNameServiceProtocol { return completion(EthereumNameServiceError.noResolver, nil) } + guard resolverData != "0x" else { + return completion(EthereumNameServiceError.ensUnknown, nil) + } + let idx = resolverData.index(resolverData.endIndex, offsetBy: -40) let resolverAddress = EthereumAddress(String(resolverData[idx...]).withHexPrefix) diff --git a/web3swift/src/ERC20/ERC20Events.swift b/web3swift/src/ERC20/ERC20Events.swift index 8c011981..755cb2cb 100644 --- a/web3swift/src/ERC20/ERC20Events.swift +++ b/web3swift/src/ERC20/ERC20Events.swift @@ -20,15 +20,14 @@ public enum ERC20Events { public let to: EthereumAddress public let value: BigUInt - public init?(topics: [String], data: [ABIType], log: EthereumLog) throws { + public init?(topics: [String], data: [String], log: EthereumLog) throws { try Transfer.checkParameters(topics, data) self.log = log self.from = try ABIDecoder.decode(topics[0], to: EthereumAddress.self) self.to = try ABIDecoder.decode(topics[1], to: EthereumAddress.self) - guard let valueStr = data[0] as? String else { return nil } - self.value = try ABIDecoder.decode(valueStr, to: BigUInt.self) + self.value = try ABIDecoder.decode(data[0], to: BigUInt.self) } } } diff --git a/web3swift/src/Extensions/HexExtensions.swift b/web3swift/src/Extensions/HexExtensions.swift index 304d7e04..62b43720 100644 --- a/web3swift/src/Extensions/HexExtensions.swift +++ b/web3swift/src/Extensions/HexExtensions.swift @@ -20,28 +20,28 @@ extension BigUInt { } public extension BigInt { - public init?(hex: String) { + init?(hex: String) { self.init(hex.noHexPrefix.lowercased(), radix: 16) } } public extension Int { - public var hexString: String { + var hexString: String { return "0x" + String(format: "%x", self) } - public init?(hex: String) { + init?(hex: String) { self.init(hex.noHexPrefix, radix: 16) } } public extension Data { - public var hexString: String { + var hexString: String { let bytes = Array(self) return "0x" + bytes.map { String(format: "%02hhx", $0) }.joined() } - public init?(hex: String) { + init?(hex: String) { if let byteArray = try? HexUtil.byteArray(fromHex: hex.noHexPrefix) { self.init(bytes: byteArray, count: byteArray.count) } else { @@ -74,7 +74,7 @@ extension String { return self } - var hexData: Data? { + public var hexData: Data? { let noHexPrefix = self.noHexPrefix if let bytes = try? HexUtil.byteArray(fromHex: noHexPrefix) { return Data(bytes: bytes) diff --git a/web3swift/src/Extensions/KeccakExtensions.swift b/web3swift/src/Extensions/KeccakExtensions.swift index b5ae65a3..50ef1c45 100644 --- a/web3swift/src/Extensions/KeccakExtensions.swift +++ b/web3swift/src/Extensions/KeccakExtensions.swift @@ -10,7 +10,7 @@ import Foundation import keccaktiny public extension Data { - public var keccak256: Data { + var keccak256: Data { let nsData = self as NSData let input = nsData.bytes.bindMemory(to: UInt8.self, capacity: self.count) let result = UnsafeMutablePointer.allocate(capacity: 32) @@ -20,12 +20,12 @@ public extension Data { } public extension String { - public var keccak256: Data { + var keccak256: Data { let data = self.data(using: .utf8) ?? Data() return data.keccak256 } - public var keccak256fromHex: Data { + var keccak256fromHex: Data { let data = self.hexData! return data.keccak256 } diff --git a/web3swift/src/Utils/KeyUtil.swift b/web3swift/src/Utils/KeyUtil.swift index e66ba1ea..c6e2d340 100644 --- a/web3swift/src/Utils/KeyUtil.swift +++ b/web3swift/src/Utils/KeyUtil.swift @@ -44,14 +44,14 @@ class KeyUtil { let outputPtr = UnsafeMutablePointer.allocate(capacity: publicKeyLength) secp256k1_ec_pubkey_serialize(ctx, outputPtr, &publicKeyLength, publicKeyPtr, UInt32(SECP256K1_EC_UNCOMPRESSED)) - let publicKey = Data(bytes: outputPtr, count: publicKeyLength).subdata(in: Range(1.. String { let hash = publicKey.keccak256 - let address = hash.subdata(in: Range(12..