Skip to content

Commit

Permalink
Merge branch 'develop' into remove-Promises
Browse files Browse the repository at this point in the history
  • Loading branch information
pharms-eth committed Apr 13, 2022
2 parents 544171e + c9b050a commit ee7e3d9
Show file tree
Hide file tree
Showing 16 changed files with 503 additions and 442 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ jobs:
run: sleep 1
- name: Run local tests
run: swift test --skip-build -c debug --filter localTests
# - name: Run remote tests
# run: swift test --skip-build -c debug --filter remoteTests
- name: Run remote tests
run: swift test --skip-build -c debug --filter remoteTests
carthage:
name: Carthage
runs-on: macOS-11
Expand All @@ -64,7 +64,7 @@ jobs:
- name: Building dependencies
run: carthage build --no-use-binaries --platform iOS Simulator --use-xcframeworks
- name: Building framework
run: xcodebuild build-for-testing -project "web3swift.xcodeproj" -scheme "web3swift" -destination "${{matrix.destination}}" -testPlan LocalTests
run: xcodebuild build-for-testing -project "web3swift.xcodeproj" -scheme "web3swift" -destination "${{matrix.destination}}"
- name: Install ganache
run: npm install ganache --global
- name: Start ganache in background
Expand All @@ -73,5 +73,5 @@ jobs:
run: sleep 1
- name: Run local tests
run: xcodebuild test-without-building -project "web3swift.xcodeproj" -scheme "web3swift" -destination "${{matrix.destination}}" -testPlan LocalTests
# - name: Run remote tests
# run: xcodebuild test-without-building -project "web3swift.xcodeproj" -scheme "web3swift" -destination "${{matrix.destination}}" -testPlan RemoteTests
- name: Run remote tests
run: xcodebuild test-without-building -project "web3swift.xcodeproj" -scheme "web3swift" -destination "${{matrix.destination}}" -testPlan RemoteTests
70 changes: 70 additions & 0 deletions CONTRIBUTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Contribution guide
## Version convention
We’re conforming [default versions convention](https://semver.org/).
So in the `1.0.0` version each position means follow:
- 1.\*.***major release**, includes API groundbreaking changes (ie: your old code will not work).
- \*.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).
- \*.*.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).

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.

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).

## What task to choose
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 "").

> 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.
## Codestyle guideline
- `swiftlint` check should goes with no warnings.
- 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).
- We use [swift](https://www.swift.org/documentation/api-design-guidelines/ "") name convention.
## Tests guideline
1. Cover each new public method with tests.
2. If you’re implementing some big feature encapsulate it in Separate file.
3. Choose one of the two directory to add test case:
* `localTests` — tests which could be ran without needing to connecting to real Ethereum network.
* `remoteTests` — tests which needing connection to real Ethereum network to be ran.
4. Exclude added file from opposite `*.xctestplan` file (e.g. if you’re adding file to `localTests` please exclude it from `RemoteTests.xctestplan`.
5. Add test file to `web3swift.xcodeproj` to make it working within Carthage building system.

## Hacks & tricks & magic
### TestPlans
In ci/cd we’re using Xcode test plans feature to spread tests to local and remote one. So any time you’re adding any new test suit (file) please exclude it from `LocalTests.xctestplan` rather `RemoteTests.xctestplan` depends on what tests group it included.
### Swift package manager
Please add any files unused due build process to `excludeFiles` array in `Package.swift`.
### Carthage
Please do not forget to add & remove all new or dropped files and dependencies in carthage `.xcodeproj` file if you’re working with project anywhere but carthage project.
### Cocoapods
Please do not forget to add & remove all dependencies within `web3swift.podspec` file.
### GitHub actions
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:

```yml
on:
push:
branches:
- master
- develop
- hotfix
- #YOUR_REPO_NAME#
```

> Please remove your branch from this list before making PR.
## Good PR checklist
### Code
- [ ] All new functionality covered by unit tests.
- [ ] Ci/cd green.
- [ ] No redundant files are added (build cache, Xcode breakpoints settings and so on).

### Info
- [ ] Relative and concrete PR title.
- [ ] Issue or roadmap goal attached.
- [ ] PR description filled with detail explanation of what it is and what’s its specific.

### Codestyle
- [ ] All public method have `///` styled comments.
- [ ] All magic or nonintuitive internal code parts are clearly explained in inline comments.
- [ ] `swiftlint` ran have no warnings.
- [ ] No commented out code lefts in PR.
20 changes: 12 additions & 8 deletions Sources/web3swift/Convenience/Decodable+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,40 +106,44 @@ extension KeyedDecodingContainer {
/// to be initialized as `BigUInt`.
public func decodeHex<T: DecodableFromHex>(to type: T.Type, key: KeyedDecodingContainer<K>.Key) throws -> T {
let string = try self.decode(String.self, forKey: key)
guard let number = T(from: string) else { throw Web3Error.dataError }
guard let number = T(fromHex: string) else { throw Web3Error.dataError }
return number
}
}

public protocol DecodableFromHex: Decodable {
init?(from hexString: String)
init?(fromHex hexString: String)
}

extension Data: DecodableFromHex {
public init?(from hexString: String) {
public init?(fromHex hexString: String) {
self.init()
guard let tmp = Self.fromHex(hexString) else { return nil }
self = tmp
}
}

extension BigUInt: DecodableFromHex {
public init?(from hexString: String) {
self.init()
guard let tmp = BigUInt(hexString.stripHexPrefix(), radix: 16) else { return nil }
self = tmp
public init?(fromHex hexString: String) {
self.init(hexString.stripHexPrefix(), radix: 16)
}
}

extension Date: DecodableFromHex {
public init?(from hexString: String) {
public init?(fromHex hexString: String) {
self.init()
let stripedHexString = hexString.stripHexPrefix()
guard let timestampInt = UInt64(stripedHexString, radix: 16) else { return nil }
self = Date(timeIntervalSince1970: TimeInterval(timestampInt))
}
}

extension EthereumAddress: DecodableFromHex {
public init?(fromHex hexString: String) {
self.init(hexString, ignoreChecksum: true)
}
}

private extension KeyedDecodingContainer {
func decode(_ type: [String: Any].Type) throws -> [String: Any] {
var dictionary: [String: Any] = [:]
Expand Down
42 changes: 22 additions & 20 deletions Sources/web3swift/Web3/Web3+EIP1559.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public extension Web3 {
/// - current: Current block
/// - Returns: True or false if block is EIP-1559 or not
static func isEip1559Block(parent: Block, current: Block) -> Bool {
let parentGasLimit = parent.chainVersion >= .London ? parent.gasLimit : parent.gasLimit * Web3.ElasticityMultiplier
let parentGasLimit = parent.mainChainVersion >= .London ? parent.gasLimit : parent.gasLimit * Web3.ElasticityMultiplier

guard verifyGasLimit(parentGasLimit: parentGasLimit, currentGasLimit: current.gasLimit) else { return false }

Expand All @@ -60,39 +60,41 @@ public extension Web3 {
///
/// Calculation for current `Block` based on parents block object only
///
/// If passed block isn't `ChainVersion.London` one will return
/// If passed block isn't `ChainVersion.London` nil will return
///
/// - Parameter parent: Parent `Block`
/// - Returns: Amount of expected base fee for current `Block`
static func calcBaseFee(_ parent: Block) -> BigUInt {
static func calcBaseFee(_ parent: Block) -> BigUInt? {
guard let parentBaseFee = parent.baseFeePerGas else { return nil }

// If given blocks ChainVersion is lower than London — always returns InitialBaseFee
guard parent.chainVersion >= .London else { return Web3.InitialBaseFee }
guard parent.mainChainVersion >= .London else { return Web3.InitialBaseFee }

let parentGasTarget = parent.gasLimit / Web3.ElasticityMultiplier

if parent.gasUsed > parentGasTarget {
// If the parent block used more gas than its target, the baseFee should increase.
let gasUsedDelta = parent.gasUsed - parentGasTarget
let baseFeePerGasDelta = max(parent.baseFeePerGas * gasUsedDelta / parentGasTarget / Web3.BaseFeeChangeDenominator, 1)
let expectedBaseFeePerGas = parent.baseFeePerGas + baseFeePerGasDelta
let baseFeePerGasDelta = max(parentBaseFee * gasUsedDelta / parentGasTarget / Web3.BaseFeeChangeDenominator, 1)
let expectedBaseFeePerGas = parentBaseFee + baseFeePerGasDelta

return expectedBaseFeePerGas
} else if parent.gasUsed < parentGasTarget {
// Otherwise if the parent block used less gas than its target, the baseFee should decrease.
let gasUsedDelta = parentGasTarget - parent.gasUsed
let baseFeePerGasDelta = parent.baseFeePerGas * gasUsedDelta / parentGasTarget / Web3.BaseFeeChangeDenominator
let expectedBaseFeePerGas = parent.baseFeePerGas - baseFeePerGasDelta
let baseFeePerGasDelta = parentBaseFee * gasUsedDelta / parentGasTarget / Web3.BaseFeeChangeDenominator
let expectedBaseFeePerGas = parentBaseFee - baseFeePerGasDelta

return expectedBaseFeePerGas
} else {
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
return parent.baseFeePerGas
return parentBaseFee
}
}
}

public extension Web3 {
enum ChainVersion: BigUInt {
enum MainChainVersion: BigUInt {
/// Byzantium switch block
///
/// Date: 16.10.2017
Expand Down Expand Up @@ -149,29 +151,29 @@ public extension Web3 {
}
}

static func getChainVersion(of block: BigUInt) -> ChainVersion {
static func getChainVersion(of block: BigUInt) -> MainChainVersion {
// Iterate given block number over each ChainVersion block numbers
// to get the block's ChainVersion.
if block < ChainVersion.Constantinople.mainNetFisrtBlockNumber {
if block < MainChainVersion.Constantinople.mainNetFisrtBlockNumber {
return .Byzantium
// ~= means included in a given range
} else if ChainVersion.Constantinople.mainNetFisrtBlockNumber..<ChainVersion.Istanbul.mainNetFisrtBlockNumber ~= block {
} else if MainChainVersion.Constantinople.mainNetFisrtBlockNumber..<MainChainVersion.Istanbul.mainNetFisrtBlockNumber ~= block {
return .Constantinople
} else if ChainVersion.Istanbul.mainNetFisrtBlockNumber..<ChainVersion.MuirGlacier.mainNetFisrtBlockNumber ~= block {
} else if MainChainVersion.Istanbul.mainNetFisrtBlockNumber..<MainChainVersion.MuirGlacier.mainNetFisrtBlockNumber ~= block {
return .Istanbul
} else if ChainVersion.MuirGlacier.mainNetFisrtBlockNumber..<ChainVersion.Berlin.mainNetFisrtBlockNumber ~= block {
} else if MainChainVersion.MuirGlacier.mainNetFisrtBlockNumber..<MainChainVersion.Berlin.mainNetFisrtBlockNumber ~= block {
return .MuirGlacier
} else if ChainVersion.Berlin.mainNetFisrtBlockNumber..<ChainVersion.London.mainNetFisrtBlockNumber ~= block {
} else if MainChainVersion.Berlin.mainNetFisrtBlockNumber..<MainChainVersion.London.mainNetFisrtBlockNumber ~= block {
return .Berlin
} else if ChainVersion.London.mainNetFisrtBlockNumber..<ChainVersion.ArrowGlacier.mainNetFisrtBlockNumber ~= block {
} else if MainChainVersion.London.mainNetFisrtBlockNumber..<MainChainVersion.ArrowGlacier.mainNetFisrtBlockNumber ~= block {
return .London
} else if block >= ChainVersion.ArrowGlacier.mainNetFisrtBlockNumber {
} else if block >= MainChainVersion.ArrowGlacier.mainNetFisrtBlockNumber {
// Pass to the default return.
}
return .ArrowGlacier
}
}

extension Web3.ChainVersion: Comparable {
public static func < (lhs: Web3.ChainVersion, rhs: Web3.ChainVersion) -> Bool { return lhs.mainNetFisrtBlockNumber < rhs.mainNetFisrtBlockNumber }
extension Web3.MainChainVersion: Comparable {
public static func < (lhs: Web3.MainChainVersion, rhs: Web3.MainChainVersion) -> Bool { return lhs.mainNetFisrtBlockNumber < rhs.mainNetFisrtBlockNumber }
}
21 changes: 12 additions & 9 deletions Sources/web3swift/Web3/Web3+JSONRPC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public struct JSONRPCresponse: Decodable{
[String: Int].self,
[String: [String: [String: [String]]]].self]

// FIXME: Make me a real generic
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: JSONRPCresponseKeys.self)
let id: Int = try container.decode(Int.self, forKey: .id)
Expand Down Expand Up @@ -163,24 +164,26 @@ public struct JSONRPCresponse: Decodable{
self.init(id: id, jsonrpc: jsonrpc, result: result, error: nil)
}

// FIXME: Make me a real generic
/// Get the JSON RCP reponse value by deserializing it into some native <T> class.
///
/// Returns nil if serialization fails
public func getValue<T>() -> T? {
let slf = T.self
if slf == BigUInt.self {
let type = T.self

if type == BigUInt.self {
guard let string = self.result as? String else {return nil}
guard let value = BigUInt(string.stripHexPrefix(), radix: 16) else {return nil}
return value as? T
} else if slf == BigInt.self {
} else if type == BigInt.self {
guard let string = self.result as? String else {return nil}
guard let value = BigInt(string.stripHexPrefix(), radix: 16) else {return nil}
return value as? T
} else if slf == Data.self {
} else if type == Data.self {
guard let string = self.result as? String else {return nil}
guard let value = Data.fromHex(string) else {return nil}
return value as? T
} else if slf == EthereumAddress.self {
} else if type == EthereumAddress.self {
guard let string = self.result as? String else {return nil}
guard let value = EthereumAddress(string, ignoreChecksum: true) else {return nil}
return value as? T
Expand All @@ -192,25 +195,25 @@ public struct JSONRPCresponse: Decodable{
// guard let value = self.result as? T else {return nil}
// return value
// }
else if slf == [BigUInt].self {
else if type == [BigUInt].self {
guard let string = self.result as? [String] else {return nil}
let values = string.compactMap { (str) -> BigUInt? in
return BigUInt(str.stripHexPrefix(), radix: 16)
}
return values as? T
} else if slf == [BigInt].self {
} else if type == [BigInt].self {
guard let string = self.result as? [String] else {return nil}
let values = string.compactMap { (str) -> BigInt? in
return BigInt(str.stripHexPrefix(), radix: 16)
}
return values as? T
} else if slf == [Data].self {
} else if type == [Data].self {
guard let string = self.result as? [String] else {return nil}
let values = string.compactMap { (str) -> Data? in
return Data.fromHex(str)
}
return values as? T
} else if slf == [EthereumAddress].self {
} else if type == [EthereumAddress].self {
guard let string = self.result as? [String] else {return nil}
let values = string.compactMap { (str) -> EthereumAddress? in
return EthereumAddress(str, ignoreChecksum: true)
Expand Down
8 changes: 5 additions & 3 deletions Sources/web3swift/Web3/Web3+Structures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ public struct Block: Decodable {
public var size: BigUInt
public var gasLimit: BigUInt
public var gasUsed: BigUInt
public var baseFeePerGas: BigUInt
public var baseFeePerGas: BigUInt?
public var timestamp: Date
public var transactions: [TransactionInBlock]
public var uncles: [Data]
Expand Down Expand Up @@ -370,7 +370,7 @@ public struct Block: Decodable {
}

/// Returns chain version of mainnet block with such number
var chainVersion: Web3.ChainVersion { Web3.getChainVersion(of: number) }
var mainChainVersion: Web3.MainChainVersion { Web3.getChainVersion(of: number) }
}

extension Block {
Expand Down Expand Up @@ -401,7 +401,9 @@ extension Block {
self.size = try container.decodeHex(to: BigUInt.self, key: .size)
self.gasLimit = try container.decodeHex(to: BigUInt.self, key: .gasLimit)
self.gasUsed = try container.decodeHex(to: BigUInt.self, key: .gasUsed)
self.baseFeePerGas = try container.decodeHex(to: BigUInt.self, key: .baseFeePerGas)

// optional, since pre EIP-1559 block haven't such property.
self.baseFeePerGas = try? container.decodeHex(to: BigUInt.self, key: .baseFeePerGas)

self.timestamp = try container.decodeHex(to: Date.self, key: .timestamp)

Expand Down
Loading

0 comments on commit ee7e3d9

Please sign in to comment.