Skip to content

Commit d8463bc

Browse files
Merge branch 'develop' into feature/gas-prediction
2 parents a51cb35 + 35746cf commit d8463bc

File tree

7 files changed

+155
-37
lines changed

7 files changed

+155
-37
lines changed

CONTRIBUTION.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Contribution guide
2+
## Version convention
3+
We’re conforming [default versions convension](https://semver.org/).
4+
So in the `1.0.0` version each position means follow:
5+
- 1.\*.***major release**, includes API groundbreaking changes (ie: your old code will not work).
6+
- \*.1.***minor release**, we’ve added some new feature to the lib, but we didn’t break something in anyway (ie: everything will work as expected without any moves after update).
7+
- \*.*.1 — **patch release**, we’re haven’t add any breaking changes or even new features for the user, but we’ve fixed some bugs or rewrote something internal (ie: you should not event mention that anything were changed in the lib).
8+
9+
This library yet living within **three weeks minor release** schedule. Also please keep in mind that in sake of avoiding complex merge conflicts, we’re currently taking only **one big feature** in release, so if you want to take some, please drop us a message somewhere to avoiding reworking it after it’ll be broken by some massive merge.
10+
11+
Critical bug fixes are should be marked with appropriate label in PR and should be proceed **within one week** till patch ’ll be released (at least we’ll try our best to made that).
12+
13+
## What task to choose
14+
Please take it from the [roadmap](https://hackmd.io/G5znP3xAQY-BVc1X8Y1jSg) or from the [opened issues](https://github.com/skywinder/web3swift/issues?q=is:issue+is:open+sort:updated-desc "").
15+
16+
> If you want to make something completely new and purely magical, please drop us a message somewhere before, since it could ends up that this is what we planning to do a lot later or that we not planning at all.
17+
18+
## Codestyle guideline
19+
- `swiftlint` check should goes with no warnings.
20+
- Here’s some more detailed and human readable code style [guidelines](https://hackmd.io/8bACoAnTSsKc55Os596yCg "") (you can add there some suggestion if you’d like to).
21+
## Tests guideline
22+
23+
24+
## Hacks & tricks & magic
25+
### TestPlans
26+
In ci/cd we’re using Xcode testplans feature to spread tests to local and remote one.
27+
### Swift package manager
28+
Please add any files unused due build process to `excludeFiles` array in `Package.swift`.
29+
### Carthage
30+
Please do not forget to add & remove all new or droped files and dependencies in carthage `.xcodeproj` file if you’re working with project anywhere but carthage project.
31+
### Cocoapods
32+
Please do not forget to add & remove all dependencies within `web3swift.podspec` file.
33+
### GitHub actions
34+
You’re able to use our github actions checks in your fork without needing to make PR to this repo. To get that just add your branch name to the branch list in file on path `.github/actions/ci.yml` to let the magic happening like follow:
35+
36+
```yml
37+
on:
38+
push:
39+
branches:
40+
- master
41+
- develop
42+
- hotfix
43+
- #YOUR_REPO_NAME#
44+
```
45+
46+
> Please remove your branch from this list before making PR.
47+
48+
## Good PR checklist
49+
### Code
50+
- [ ] All new functionality covered by unit tests.
51+
- [ ] Ci/cd green.
52+
- [ ] No redundant files are added (build cache, Xcode breakpoints settings and so on).
53+
54+
### Info
55+
- [ ] Relative and concrete PR title.
56+
- [ ] Issue or roadmap goal attached.
57+
- [ ] PR description filled with detail explanation of what it is and what’s its specific.
58+
59+
### Codestyle
60+
- [ ] All public method have `///` styled comments.
61+
- [ ] All magic or nonintuitive internal code parts are clearly explained in inline comments.
62+
- [ ] `swiftlint` ran have no warnings.
63+
- [ ] No commented out code lefts in PR.
64+
65+

Sources/web3swift/EthereumABI/ABIElements.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public extension ABI {
4444
case fallback(Fallback)
4545
case event(Event)
4646
case receive(Receive)
47+
case error(EthError)
4748

4849
public enum StateMutability {
4950
case payable
@@ -152,6 +153,21 @@ public extension ABI {
152153
self.payable = payable
153154
}
154155
}
156+
/// Custom structured error type available since solidity 0.8.4
157+
public struct EthError {
158+
public let name: String
159+
public let inputs: [Input]
160+
161+
public struct Input {
162+
public let name: String
163+
public let type: ParameterType
164+
165+
public init(name: String, type: ParameterType) {
166+
self.name = name
167+
self.type = type
168+
}
169+
}
170+
}
155171
}
156172
}
157173

@@ -173,6 +189,8 @@ extension ABI.Element {
173189
return signature + data
174190
case .receive(_):
175191
return nil
192+
case .error(_):
193+
return nil
176194
}
177195
}
178196
}
@@ -249,6 +267,8 @@ extension ABI.Element {
249267
return returnArray
250268
case .receive(_):
251269
return nil
270+
case .error(_):
271+
return nil
252272
}
253273
}
254274

@@ -324,6 +344,8 @@ extension ABI.Element {
324344
return returnArray
325345
case .receive(_):
326346
return nil
347+
case .error(_):
348+
return nil
327349
}
328350
}
329351
}

Sources/web3swift/EthereumABI/ABIParsing.swift

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@ extension ABI {
3030
case fallback
3131
case event
3232
case receive
33+
case error
3334
}
3435

3536
}
3637

3738
extension ABI.Record {
3839
public func parse() throws -> ABI.Element {
39-
let typeString = self.type != nil ? self.type! : "function"
40+
let typeString = self.type ?? "function"
4041
guard let type = ABI.ElementType(rawValue: typeString) else {
4142
throw ABI.ParsingError.elementTypeInvalid
4243
}
@@ -61,6 +62,9 @@ fileprivate func parseToElement(from abiRecord: ABI.Record, type: ABI.ElementTyp
6162
case .receive:
6263
let receive = try parseReceive(abiRecord: abiRecord)
6364
return ABI.Element.receive(receive)
65+
case .error:
66+
let error = try parseError(abiRecord: abiRecord)
67+
return ABI.Element.error(error)
6468
}
6569

6670
}
@@ -70,26 +74,22 @@ fileprivate func parseFunction(abiRecord: ABI.Record) throws -> ABI.Element.Func
7074
let nativeInput = try input.parse()
7175
return nativeInput
7276
})
73-
let abiInputs = inputs != nil ? inputs! : [ABI.Element.InOut]()
74-
let outputs = try abiRecord.outputs?.map({ (output: ABI.Output) throws -> ABI.Element.InOut in
77+
let abiInputs = inputs ?? [ABI.Element.InOut]()
78+
let outputs = try abiRecord.outputs?.map({ (output:ABI.Output) throws -> ABI.Element.InOut in
7579
let nativeOutput = try output.parse()
7680
return nativeOutput
7781
})
78-
let abiOutputs = outputs != nil ? outputs! : [ABI.Element.InOut]()
79-
let name = abiRecord.name != nil ? abiRecord.name! : ""
80-
let payable = abiRecord.stateMutability != nil ?
81-
(abiRecord.stateMutability == "payable" || abiRecord.payable ?? false) : false
82-
let constant = (abiRecord.constant == true || abiRecord.stateMutability == "view" || abiRecord.stateMutability == "pure")
82+
let abiOutputs = outputs ?? [ABI.Element.InOut]()
83+
let name = abiRecord.name ?? ""
84+
let payable = abiRecord.stateMutability == "payable" || abiRecord.payable == true
85+
let constant = abiRecord.constant == true || abiRecord.stateMutability == "view" || abiRecord.stateMutability == "pure"
8386
let functionElement = ABI.Element.Function(name: name, inputs: abiInputs, outputs: abiOutputs, constant: constant, payable: payable)
8487
return functionElement
8588
}
8689

8790
fileprivate func parseFallback(abiRecord: ABI.Record) throws -> ABI.Element.Fallback {
8891
let payable = (abiRecord.stateMutability == "payable" || abiRecord.payable == true)
89-
var constant = abiRecord.constant == true
90-
if (abiRecord.stateMutability == "view" || abiRecord.stateMutability == "pure") {
91-
constant = true
92-
}
92+
let constant = abiRecord.constant == true || abiRecord.stateMutability == "view" || abiRecord.stateMutability == "pure"
9393
let functionElement = ABI.Element.Fallback(constant: constant, payable: payable)
9494
return functionElement
9595
}
@@ -99,16 +99,9 @@ fileprivate func parseConstructor(abiRecord: ABI.Record) throws -> ABI.Element.C
9999
let nativeInput = try input.parse()
100100
return nativeInput
101101
})
102-
let abiInputs = inputs != nil ? inputs! : [ABI.Element.InOut]()
103-
var payable = false
104-
if (abiRecord.payable != nil) {
105-
payable = abiRecord.payable!
106-
}
107-
if (abiRecord.stateMutability == "payable") {
108-
payable = true
109-
}
110-
let constant = false
111-
let functionElement = ABI.Element.Constructor(inputs: abiInputs, constant: constant, payable: payable)
102+
let abiInputs = inputs ?? [ABI.Element.InOut]()
103+
let payable = abiRecord.stateMutability == "payable" || abiRecord.payable == true
104+
let functionElement = ABI.Element.Constructor(inputs: abiInputs, constant: false, payable: payable)
112105
return functionElement
113106
}
114107

@@ -117,9 +110,9 @@ fileprivate func parseEvent(abiRecord: ABI.Record) throws -> ABI.Element.Event {
117110
let nativeInput = try input.parseForEvent()
118111
return nativeInput
119112
})
120-
let abiInputs = inputs != nil ? inputs! : [ABI.Element.Event.Input]()
121-
let name = abiRecord.name != nil ? abiRecord.name! : ""
122-
let anonymous = abiRecord.anonymous != nil ? abiRecord.anonymous! : false
113+
let abiInputs = inputs ?? [ABI.Element.Event.Input]()
114+
let name = abiRecord.name ?? ""
115+
let anonymous = abiRecord.anonymous ?? false
123116
let functionElement = ABI.Element.Event(name: name, inputs: abiInputs, anonymous: anonymous)
124117
return functionElement
125118
}
@@ -129,21 +122,25 @@ fileprivate func parseReceive(abiRecord: ABI.Record) throws -> ABI.Element.Recei
129122
let nativeInput = try input.parse()
130123
return nativeInput
131124
})
132-
let abiInputs = inputs != nil ? inputs! : [ABI.Element.InOut]()
133-
var payable = false
134-
if (abiRecord.payable != nil) {
135-
payable = abiRecord.payable!
136-
}
137-
if (abiRecord.stateMutability == "payable") {
138-
payable = true
139-
}
125+
let abiInputs = inputs ?? [ABI.Element.InOut]()
126+
let payable = abiRecord.stateMutability == "payable" || abiRecord.payable == true
140127
let functionElement = ABI.Element.Receive(inputs: abiInputs, payable: payable)
141128
return functionElement
142129
}
143130

131+
fileprivate func parseError(abiRecord:ABI.Record) throws -> ABI.Element.EthError {
132+
let inputs = try abiRecord.inputs?.map({ (input:ABI.Input) throws -> ABI.Element.EthError.Input in
133+
let nativeInput = try input.parseForError()
134+
return nativeInput
135+
})
136+
let abiInputs = inputs ?? []
137+
let name = abiRecord.name ?? ""
138+
return ABI.Element.EthError(name: name, inputs: abiInputs)
139+
}
140+
144141
extension ABI.Input {
145142
func parse() throws -> ABI.Element.InOut {
146-
let name = self.name != nil ? self.name! : ""
143+
let name = self.name ?? ""
147144
let parameterType = try ABITypeParser.parseTypeString(self.type)
148145
if case .tuple(types: _) = parameterType {
149146
let components = try self.components?.compactMap({ (inp: ABI.Input) throws -> ABI.Element.ParameterType in
@@ -171,12 +168,18 @@ extension ABI.Input {
171168
}
172169
}
173170

174-
func parseForEvent() throws -> ABI.Element.Event.Input{
175-
let name = self.name != nil ? self.name! : ""
171+
func parseForEvent() throws -> ABI.Element.Event.Input {
172+
let name = self.name ?? ""
176173
let parameterType = try ABITypeParser.parseTypeString(self.type)
177174
let indexed = self.indexed == true
178175
return ABI.Element.Event.Input(name: name, type: parameterType, indexed: indexed)
179176
}
177+
178+
func parseForError() throws -> ABI.Element.EthError.Input {
179+
let name = self.name ?? ""
180+
let parameterType = try ABITypeParser.parseTypeString(self.type)
181+
return ABI.Element.EthError.Input(name:name, type: parameterType)
182+
}
180183
}
181184

182185
extension ABI.Output {

Sources/web3swift/Web3/Web3+InfuraProviders.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public enum BlockNumber {
3131
public final class InfuraProvider: Web3HttpProvider {
3232
public init?(_ net: Networks, accessToken token: String? = nil, keystoreManager manager: KeystoreManager? = nil) {
3333
var requestURLstring = "https://" + net.name + Constants.infuraHttpScheme
34-
requestURLstring += token != nil ? token! : Constants.infuraToken
34+
requestURLstring += token ?? Constants.infuraToken
3535
let providerURL = URL(string: requestURLstring)
3636
super.init(providerURL!, network: net, keystoreManager: manager)
3737
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//
2+
// web3swiftDecodeSolidityErrorType.swift
3+
// Tests
4+
//
5+
// Created by JeneaVranceanu on 25/01/2022.
6+
// Copyright © 2022 web3swift. All rights reserved.
7+
//
8+
9+
import XCTest
10+
import web3swift
11+
12+
/// Since solidity 0.8.4 a new type was introduced called `error`.
13+
/// Contracts' ABI with this type were not decodable.
14+
class web3swiftDecodeSolidityErrorType: XCTestCase {
15+
16+
func testStructuredErrorTypeDecoding() throws {
17+
let contractAbiWithErrorTypes = "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"disallowedAddress\",\"type\":\"address\"}],\"name\":\"NotAllowedAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"disallowedFunction\",\"type\":\"bytes4\"}],\"name\":\"NotAllowedFunction\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"permission\",\"type\":\"string\"}],\"name\":\"NotAuthorised\",\"type\":\"error\"}]"
18+
let web3Instance = try Web3.new(URL.init(string: "http://127.0.0.1:8545")!)
19+
let contract = web3.web3contract(web3: web3Instance, abiString: contractAbiWithErrorTypes)
20+
assert(contract != nil)
21+
}
22+
}

Tests/web3swiftTests/remoteTests/RemoteTests.xctestplan

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"SoliditySha3Test",
2222
"web3swiftAdvancedABIv2Tests",
2323
"web3swiftBasicLocalNodeTests",
24+
"web3swiftDecodeSolidityErrorType",
2425
"web3swiftEIP67Tests",
2526
"web3swiftEIP681Tests",
2627
"web3swiftERC20ClassTests",

web3swift.xcodeproj/project.pbxproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@
194194
5CF7E8BC276B79380009900F /* web3swiftWebsocketTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF7E8B7276B79380009900F /* web3swiftWebsocketTests.swift */; };
195195
604FA4FF27ECBDC80021108F /* DataConversionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 604FA4FE27ECBDC80021108F /* DataConversionTests.swift */; };
196196
CB50A52827060BD600D7E39B /* EIP712Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB50A52727060BD600D7E39B /* EIP712Tests.swift */; };
197+
D606A56B279F5D59003643ED /* web3swiftDecodeSolidityErrorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D606A56A279F5D59003643ED /* web3swiftDecodeSolidityErrorType.swift */; };
197198
D6A3D9B827F1E785009E3BCF /* ABIEncoderSoliditySha3Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3D9B727F1E785009E3BCF /* ABIEncoderSoliditySha3Test.swift */; };
198199
E22A911F241ED71A00EC1021 /* browser.min.js in Resources */ = {isa = PBXBuildFile; fileRef = E22A911E241ED71A00EC1021 /* browser.min.js */; };
199200
E2B76710241ED479007EBFE3 /* browser.js in Resources */ = {isa = PBXBuildFile; fileRef = E2B7670F241ED479007EBFE3 /* browser.js */; };
@@ -416,6 +417,7 @@
416417
604FA4FE27ECBDC80021108F /* DataConversionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataConversionTests.swift; sourceTree = "<group>"; };
417418
CB50A52727060BD600D7E39B /* EIP712Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EIP712Tests.swift; sourceTree = "<group>"; };
418419
CB50A52927060C5300D7E39B /* EIP712.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EIP712.swift; sourceTree = "<group>"; };
420+
D606A56A279F5D59003643ED /* web3swiftDecodeSolidityErrorType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = web3swiftDecodeSolidityErrorType.swift; sourceTree = "<group>"; };
419421
D6A3D9B727F1E785009E3BCF /* ABIEncoderSoliditySha3Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ABIEncoderSoliditySha3Test.swift; sourceTree = "<group>"; };
420422
E22A911E241ED71A00EC1021 /* browser.min.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = browser.min.js; sourceTree = "<group>"; };
421423
E2B7670F241ED479007EBFE3 /* browser.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = browser.js; sourceTree = "<group>"; };
@@ -1014,6 +1016,7 @@
10141016
CB50A52727060BD600D7E39B /* EIP712Tests.swift */,
10151017
D6A3D9B727F1E785009E3BCF /* ABIEncoderSoliditySha3Test.swift */,
10161018
5CDEF973275A74670004A2F2 /* LocalTests.xctestplan */,
1019+
D606A56A279F5D59003643ED /* web3swiftDecodeSolidityErrorType.swift */,
10171020
);
10181021
path = localTests;
10191022
sourceTree = "<group>";
@@ -1386,6 +1389,8 @@
13861389
isa = PBXSourcesBuildPhase;
13871390
buildActionMask = 2147483647;
13881391
files = (
1392+
CB50A52827060BD600D7E39B /* EIP712Tests.swift in Sources */,
1393+
D606A56B279F5D59003643ED /* web3swiftDecodeSolidityErrorType.swift in Sources */,
13891394
5CF7E8AB276B792A0009900F /* web3swiftTests.swift in Sources */,
13901395
5CF7E8A4276B792A0009900F /* web3swiftTransactionsTests.swift in Sources */,
13911396
5C26D8A027F3725500431EB0 /* EIP1559BlockTests.swift in Sources */,

0 commit comments

Comments
 (0)