Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@
import Foundation

extension RequestParameter: Encodable {
/**
This encoder encodes `RequestParameter` associated value ignoring self value

This is required to encode mixed types array, like

```swift
let someArray: [RequestParameter] = [
.init(rawValue: 12)!,
.init(rawValue: "this")!,
.init(rawValue: 12.2)!,
.init(rawValue: [12.2, 12.4])!
]
let encoded = try JSONEncoder().encode(someArray)
print(String(data: encoded, encoding: .utf8)!)
//> [12,\"this\",12.2,[12.2,12.4]]`
```
*/

/// This encoder encodes `RequestParameter` associated value ignoring self value
///
/// This is required to encode mixed types array, like
///
/// ```swift
/// let someArray: [RequestParameter] = [
/// .init(rawValue: 12)!,
/// .init(rawValue: "this")!,
/// .init(rawValue: 12.2)!,
/// .init(rawValue: [12.2, 12.4])!
/// ]
/// let encoded = try JSONEncoder().encode(someArray)
/// print(String(data: encoded, encoding: .utf8)!)
/// //> [12,\"this\",12.2,[12.2,12.4]]`
/// ```
/// - Parameter encoder: The encoder to write data to.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This format of multiline documentation (using /// instead of /** */) is even used by Apple.
And to me personally, it looks a lot easier to edit.

Copy link
Collaborator

Choose a reason for hiding this comment

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

While i have no pref about the doc style, i have to say, that this is true only if you're staying within Xcode. All third party editor knows nothing about /// comments, and not prefix it on new line hit.

Actually because i did wrote those comments in Sublime Text i'd choose the given one doc style formatting.

func encode(to encoder: Encoder) throws {
var enumContainer = encoder.singleValueContainer()
/// force casting in this switch is safe because
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
import Foundation

extension RequestParameter: RawRepresentable {
/**
This init is required by ``RawRepresentable`` protocol, which is required to encode mixed type values array in JSON.

This protocol is used to implement custom `encode` method for that enum,
which encodes an array of self-assosiated values.

You're totally free to use explicit and more convenience member init as `RequestParameter.int(12)` in your code.
*/
/// This init is required by ``RawRepresentable`` protocol, which is required
/// to encode mixed type values array in JSON.
///
/// This protocol is used to implement custom `encode` method for that enum,
/// which encodes an array of self-assosiated values.
///
/// You're totally free to use explicit and more convenience member init as `RequestParameter.int(12)` in your code.
/// - Parameter rawValue: one of the supported types like `Int`, `UInt` etc.
init?(rawValue: APIRequestParameterType) {
/// force casting in this switch is safe because
/// each `rawValue` forced to casts only in exact case which is runs based on `rawValues` type
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,41 @@
//
// RequestParameter.swift
//
//
//
// Created by Yaroslav Yashin on 12.07.2022.
//

import Foundation

/**
Enum to compose request to the node params.

In most cases request params are passed to Ethereum JSON RPC request as array of mixed type values, such as `[12,"this",true]`.

Meanwhile swift don't provide strict way to compose such array it gives some hacks to solve this task
and one of them is using `RawRepresentable` protocol.

This protocol allows the designated type to represent itself in `String` representation.

So in our case we're using it to implement custom `encode` method for all possible types used as request params.

This `encode` method is required to encode array of `RequestParameter` to not to `[RequestParameter.int(1)]`, but to `[1]`.

Here's an example of using this enum in field.
```swift
let jsonRPCParams: [APIRequestParameterType] = [
.init(rawValue: 12)!,
.init(rawValue: "this")!,
.init(rawValue: 12.2)!,
.init(rawValue: [12.2, 12.4])!
]
let encoded = try JSONEncoder().encode(jsonRPCParams)
print(String(data: encoded, encoding: .utf8)!)
//> [12,\"this\",12.2,[12.2,12.4]]`
```
*/
/// Enum to compose request to the node params.
///
/// In most cases request params are passed to Ethereum JSON RPC request as array of
/// mixed type values, such as `[12,"this",true]`.
///
/// Meanwhile swift don't provide strict way to compose such array it gives
/// some hacks to solve this task
/// and one of them is using `RawRepresentable` protocol.
///
/// This protocol allows the designated type to represent itself in `String` representation.
///
/// So in our case we're using it to implement custom `encode` method for all possible
/// types used as request params.
///
/// This `encode` method is required to encode array of `RequestParameter`
/// to not to `[RequestParameter.int(1)]`, but to `[1]`.
///
/// Here's an example of using this enum in field.
/// ```swift
/// let jsonRPCParams: [APIRequestParameterType] = [
/// .init(rawValue: 12)!,
/// .init(rawValue: "this")!,
/// .init(rawValue: 12.2)!,
/// .init(rawValue: [12.2, 12.4])!
/// ]
/// let encoded = try JSONEncoder().encode(jsonRPCParams)
/// print(String(data: encoded, encoding: .utf8)!)
/// //> [12,\"this\",12.2,[12.2,12.4]]`
/// ```
enum RequestParameter {
case int(Int)
case intArray([Int])
Expand Down
2 changes: 1 addition & 1 deletion Sources/Web3Core/KeystoreManager/BIP32HDNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public class HDNode {
let hmacKey = "Bitcoin seed".data(using: .ascii)!
let hmac: Authenticator = HMAC(key: hmacKey.bytes, variant: HMAC.Variant.sha2(.sha512))
guard let entropy = try? hmac.authenticate(seed.bytes) else { return nil }
guard entropy.count == 64 else { return nil}
guard entropy.count == 64 else { return nil }
let I_L = entropy[0..<32]
let I_R = entropy[32..<64]
chaincode = Data(I_R)
Expand Down
46 changes: 21 additions & 25 deletions Sources/Web3Core/KeystoreManager/BIP44.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@
import Foundation

public protocol BIP44 {
/**
Derive an ``HDNode`` based on the provided path. The function will throw ``BIP44Error.warning`` if it was invoked with `throwOnWarning` equal to
`true` and the root key doesn't have a previous child with at least one transaction. If it is invoked with `throwOnWarning` equal to `false` the child node will be
derived directly using the derive function of ``HDNode``. This function needs to query the blockchain history when `throwOnWarning` is `true`, so it can throw
network errors.
- Parameter path: valid BIP44 path.
- Parameter throwOnWarning: `true` to use
[Account Discovery](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#account-discovery) standard,
otherwise it will dervive the key using the derive function of ``HDNode``.
- Throws: ``BIP44Error.warning`` if the child key shouldn't be used according to
[Account Discovery](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#account-discovery) standard.
- Returns: an ``HDNode`` child key for the provided `path` if it can be created, otherwise `nil`
*/
/// Derive an ``HDNode`` based on the provided path. The function will throw ``BIP44Error.warning``
/// if it was invoked with `throwOnWarning` equal to `true` and the root key doesn't have a previous child
/// with at least one transaction. If it is invoked with `throwOnWarning` equal to `false` the child node will
/// be derived directly using the derive function of ``HDNode``. This function needs to query the blockchain
/// history when `throwOnWarning` is `true`, so it can throw network errors.
/// - Parameter path: valid BIP44 path.
/// - Parameter throwOnWarning: `true` to use
/// [Account Discovery](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#account-discovery) standard,
/// otherwise it will dervive the key using the derive function of ``HDNode``.
/// - Throws: ``BIP44Error.warning`` if the child key shouldn't be used according to
/// [Account Discovery](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#account-discovery) standard.
/// - Returns: an ``HDNode`` child key for the provided `path` if it can be created, otherwise `nil`
func derive(path: String, throwOnWarning: Bool, transactionChecker: TransactionChecker) async throws -> HDNode?
}

Expand All @@ -35,12 +34,10 @@ public enum BIP44Error: LocalizedError, Equatable {
}

public protocol TransactionChecker {
/**
It verifies if the provided address has at least one transaction
- Parameter address: to be queried
- Throws: any error related to query the blockchain provider
- Returns: `true` if the address has at least one transaction, `false` otherwise
*/
/// It verifies if the provided address has at least one transaction
/// - Parameter ethereumAddress: to be queried
/// - Throws: any error related to query the blockchain provider
/// - Returns: `true` if the address has at least one transaction, `false` otherwise
func hasTransactions(ethereumAddress: EthereumAddress) async throws -> Bool
}

Expand Down Expand Up @@ -104,12 +101,11 @@ extension String {
return account
}

/**
Transforms a bip44 path into a new one changing account & index. The resulting one will have the change value equal to `0` to represent the external chain. The format will be `m/44'/coin_type'/account'/change/address_index`
- Parameter account: the new account to use
- Parameter addressIndex: the new addressIndex to use
- Returns: a valid bip44 path with the provided account, addressIndex and external change or `nil` otherwise
*/
/// Transforms a bip44 path into a new one changing account & index. The resulting one will have the change value equal to `0` to
/// represent the external chain. The format will be `m/44'/coin_type'/account'/change/address_index`
/// - Parameter account: the new account to use
/// - Parameter addressIndex: the new addressIndex to use
/// - Returns: a valid bip44 path with the provided account, addressIndex and external change or `nil` otherwise
func newPath(account: Int, addressIndex: Int) -> String? {
guard isBip44Path else {
return nil
Expand Down
74 changes: 36 additions & 38 deletions Sources/Web3Core/Transaction/EventfilterParameters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,44 +56,42 @@ extension EventFilterParameters {
}

extension EventFilterParameters {
/**
This enum covers the optional nested Arrays

``EventFilterParameters`` include ``topic`` property with is array of optional values,
and where `nil` value is a thing, and should be kept in server request.

This is not a trivial case for swift lang or any other stricktly typed lang.

So to make this possible ``Topic`` enum is provided.

It handle two cases: ``.string(String?)`` and ``.strings([Topic?]?)``,
where former should be used to assign first demention value,
and the latter to assign second dimension value into ``EventFilterParameters.topics`` property.

So to encode as a parameter follow JSON array:
```JSON
[
"0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
null,
[
"0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"
]
]
```

you have to pass to the ``topics`` property follow swift array:
```swift
let topics: [Topic?] = [
.string("0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
.string(nil),
.strings([
.string("0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
.string("0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"),
])
]
```
*/
/// This enum covers the optional nested Arrays
///
/// ``EventFilterParameters`` include ``topic`` property with is array of optional values,
/// and where `nil` value is a thing, and should be kept in server request.
///
/// This is not a trivial case for swift lang or any other stricktly typed lang.
///
/// So to make this possible ``Topic`` enum is provided.
///
/// It handle two cases: ``.string(String?)`` and ``.strings([Topic?]?)``,
/// where former should be used to assign first demention value,
/// and the latter to assign second dimension value into ``EventFilterParameters.topics`` property.
///
/// So to encode as a parameter follow JSON array:
/// ```JSON
/// [
/// "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
/// null,
/// [
/// "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
/// "0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"
/// ]
/// ]
/// ```
///
/// you have to pass to the ``topics`` property follow swift array:
/// ```swift
/// let topics: [Topic?] = [
/// .string("0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
/// .string(nil),
/// .strings([
/// .string("0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
/// .string("0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"),
/// ])
/// ]
/// ```
public enum Topic: Encodable {
case string(String?)
case strings([Topic?]?)
Expand Down
10 changes: 3 additions & 7 deletions Sources/Web3Core/Utility/Utilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,9 @@ public struct Utilities {
}

/// Recover the Ethereum address from recoverable secp256k1 signature. Message is first hashed using the "personal hash" protocol.
/// BE WARNED - changing a message will result in different Ethereum address, but not in error.
///
/// Input parameters should be Data objects.
/// BE WARNED - changing a message will result in different Ethereum address, but not in an error.
public static func personalECRecover(_ personalMessage: Data, signature: Data) -> EthereumAddress? {
if signature.count != 65 { return nil}
if signature.count != 65 { return nil }
let rData = signature[0..<32].bytes
let sData = signature[32..<64].bytes
var vData = signature[64]
Expand All @@ -226,10 +224,8 @@ public struct Utilities {

/// Recover the Ethereum address from recoverable secp256k1 signature.
/// Takes a hash of some message. What message is hashed should be checked by user separately.
///
/// Input parameters should be Data objects.
public static func hashECRecover(hash: Data, signature: Data) -> EthereumAddress? {
if signature.count != 65 { return nil}
if signature.count != 65 { return nil }
let rData = signature[0..<32].bytes
let sData = signature[32..<64].bytes
var vData = signature[64]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ extension Web3.BrowserFunctions {
}

public func personalECRecover(_ personalMessage: Data, signature: Data) -> String? {
if signature.count != 65 { return nil}
if signature.count != 65 { return nil }
let rData = signature[0..<32].bytes
let sData = signature[32..<64].bytes
var vData = signature[64]
Expand Down
Loading