Skip to content

Commit 08ddc4f

Browse files
committed
added string utils to obtain the external address of a path
1 parent 8d5411b commit 08ddc4f

File tree

3 files changed

+110
-2
lines changed

3 files changed

+110
-2
lines changed

Sources/Web3Core/KeystoreManager/BIP44.swift

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,48 @@ public enum BIP44Error: Equatable {
2525
extension HDNode: BIP44 {
2626
public func derive(path: String, warns: Bool = true) async throws -> HDNode? {
2727
if warns {
28-
// https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#account-discovery
28+
if let externalPath = path.externalChangePath {
29+
30+
}
2931
return nil
3032
} else {
3133
return derive(path: path, derivePrivateKey: true)
3234
}
3335
}
3436
}
37+
38+
extension String {
39+
/// Returns a new BIP32 path that uses an external change, if the path is invalid returns nil
40+
var externalChangePath: String? {
41+
do {
42+
guard isBip44Path else {
43+
return nil
44+
}
45+
let changePathPattern = "'/[0-1]/"
46+
let regex = try NSRegularExpression(pattern: changePathPattern, options: [.caseInsensitive])
47+
let range = NSRange(location: 0, length: utf16.count)
48+
let matches = regex.numberOfMatches(in: self, range: range)
49+
if matches == 1 {
50+
let result = regex.stringByReplacingMatches(in: self, options: [], range: range, withTemplate: "'/0/")
51+
return result
52+
} else {
53+
return nil
54+
}
55+
} catch {
56+
return nil
57+
}
58+
}
59+
60+
/// Verifies if matches BIP44 path standard
61+
var isBip44Path: Bool {
62+
do {
63+
let pattern = "^m/44'/\\d+'/\\d+'/[0-1]/\\d+$"
64+
let regex = try NSRegularExpression(pattern: pattern, options: [.caseInsensitive])
65+
let matches = regex.numberOfMatches(in: self, range: NSRange(location: 0, length: utf16.count))
66+
return matches == 1
67+
} catch {
68+
return false
69+
}
70+
}
71+
}
72+

Tests/web3swiftTests/localTests/BIP44Tests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import XCTest
77
import Web3Core
88
@testable import web3swift
99

10-
final class BIP44Tests: XCTestCase {
10+
final class BIP44Tests: LocalTestCase {
1111

1212
private let mnemonic = "fruit wave dwarf banana earth journey tattoo true farm silk olive fence"
1313

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//
2+
// StringBIP44Tests.swift
3+
// Created by Alberto Penas Amor on 18/12/22.
4+
//
5+
6+
import XCTest
7+
@testable import Web3Core
8+
9+
final class StringBIP44Tests: XCTestCase {
10+
11+
//MARK: - externalChangePath
12+
13+
func testInvalidChangesReturnNil() throws {
14+
let invalidPaths = ["m/44'/60'/0'/-1/0",
15+
"m/44'/60'/0'/2/0"]
16+
invalidPaths.forEach { invalidPath in
17+
XCTAssertNil(invalidPath.externalChangePath)
18+
}
19+
}
20+
21+
func testInternalChangeReturnsExternalChangePath() throws {
22+
let path = "m/44'/60'/0'/1/0"
23+
let result = path.externalChangePath
24+
XCTAssertEqual(result, "m/44'/60'/0'/0/0")
25+
}
26+
27+
func testExternalChangeReturnsExternalChangePath() throws {
28+
let path = "m/44'/60'/0'/0/0"
29+
let result = path.externalChangePath
30+
XCTAssertEqual(result, path)
31+
}
32+
33+
//MARK: - isBip44Path
34+
35+
func testVerifyBip44Paths() {
36+
let validPaths = ["m/44'/0'/0'/0/0",
37+
"m/44'/1'/0'/0/0",
38+
"m/44'/0'/1'/0/0",
39+
"m/44'/0'/0'/1/0",
40+
"m/44'/0'/0'/0/1"]
41+
validPaths.forEach { validPath in
42+
let result = validPath.isBip44Path
43+
XCTAssertTrue(result)
44+
}
45+
}
46+
47+
func testVerifyNotBip44Paths() {
48+
let invalidPaths = ["",
49+
"/44'/60'/0'/0/0",
50+
"m44'/60'/0'/0/0",
51+
"m0'/60'/0'/0/0",
52+
"m/'/60'/0'/0/0",
53+
"m/60'/0'/0/0",
54+
"m/44'/60/0'/0/0",
55+
"m/44'/'/0'/0/0",
56+
"m/44'/60'/0/0/0",
57+
"m/44'/60'/'/0/0",
58+
"m/44'/60'/0'/0",
59+
"m/44'/60'/0'/0/",
60+
"m/44'/60'/0'/-1/0",
61+
"m/44'/60'/0'/2/0",
62+
"m/44'/60.0'/0'/0/0",
63+
"m/44'/60'/0.0'/0/0",
64+
"m/44'/60'/0'/0/0.0"]
65+
invalidPaths.forEach { invalidPath in
66+
let result = invalidPath.isBip44Path
67+
XCTAssertFalse(result)
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)