Skip to content

Commit 2af0c71

Browse files
authored
Addresses generator (#1)
- Generation amount of addresses added - Generation wallet with index > 9 fixed - Test generation addresses added
1 parent d7f5a95 commit 2af0c71

File tree

2 files changed

+105
-2
lines changed

2 files changed

+105
-2
lines changed

Sources/Web3Core/KeystoreManager/BIP32Keystore.swift

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ public class BIP32Keystore: AbstractKeystore {
177177
if path.hasPrefix(prefixPath) {
178178
let upperIndex = (path.range(of: prefixPath)?.upperBound)!
179179
if upperIndex < path.endIndex {
180-
pathAppendix = String(path[path.index(after: upperIndex)])
180+
pathAppendix = String(path[path.index(after: upperIndex)..<path.endIndex])
181181
} else {
182182
throw AbstractKeystoreError.encryptionError("out of bounds")
183183
}
@@ -215,7 +215,56 @@ public class BIP32Keystore: AbstractKeystore {
215215
guard let serializedRootNode = rootNode.serialize(serializePublic: false) else {throw AbstractKeystoreError.keyDerivationError}
216216
try encryptDataToStorage(password, data: serializedRootNode, aesMode: self.keystoreParams!.crypto.cipher)
217217
}
218-
218+
219+
/// Fast generation addresses for current account
220+
/// used for shows wich address user wiil get when changed number of his wallet
221+
/// - Parameters:
222+
/// - password: password of seed storage
223+
/// - preffixPath: preffix of Derivation Path without account number
224+
/// - number: number of wallets adresses needed to generate from 0 to number-1
225+
/// - Returns: Array of addresses generated from 0 to number bound, or empty array in case of error
226+
public func getAddressForAccount(password: String, preffixPath: String, number: Int) -> [EthereumAddress] {
227+
guard let decryptedRootNode = try? getPrefixNodeData(password) else {
228+
return []
229+
}
230+
guard let rootNode = HDNode(decryptedRootNode) else {
231+
return []
232+
}
233+
let prefixPath = self.rootPrefix
234+
var pathAppendix: String?
235+
236+
return [Int](0..<number).compactMap({ number in
237+
pathAppendix = nil
238+
let path = preffixPath + "/\(number)"
239+
if path.hasPrefix(prefixPath) {
240+
let upperIndex = (path.range(of: prefixPath)?.upperBound)!
241+
if upperIndex < path.endIndex {
242+
pathAppendix = String(path[path.index(after: upperIndex)..<path.endIndex])
243+
} else {
244+
return nil
245+
}
246+
247+
guard pathAppendix != nil else {
248+
return nil
249+
}
250+
if pathAppendix!.hasPrefix("/") {
251+
pathAppendix = pathAppendix?.trimmingCharacters(in: CharacterSet.init(charactersIn: "/"))
252+
}
253+
} else {
254+
if path.hasPrefix("/") {
255+
pathAppendix = path.trimmingCharacters(in: CharacterSet.init(charactersIn: "/"))
256+
}
257+
}
258+
guard pathAppendix != nil,
259+
rootNode.depth == prefixPath.components(separatedBy: "/").count - 1,
260+
let newNode = rootNode.derive(path: pathAppendix!, derivePrivateKey: true),
261+
let newAddress = Utilities.publicToAddress(newNode.publicKey) else {
262+
return nil
263+
}
264+
return newAddress
265+
})
266+
}
267+
219268
fileprivate func encryptDataToStorage(_ password: String, data: Data, dkLen: Int = 32, N: Int = 4096, R: Int = 6, P: Int = 1, aesMode: String = "aes-128-cbc") throws {
220269
guard data.count == 82 else {
221270
throw AbstractKeystoreError.encryptionError("Invalid expected data length")
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//
2+
// BIP32KeystoreTests.swift
3+
// localTests
4+
//
5+
// Created by 6od9i on 29.06.2023.
6+
//
7+
8+
import Foundation
9+
import XCTest
10+
import Web3Core
11+
12+
@testable import web3swift
13+
14+
class BIP32KeystoreTests: XCTestCase {
15+
func testAddressGeneration() throws {
16+
/// Seed randomly generated for this test
17+
let mnemonic = "resource beyond merit enemy foot piece reveal eagle nothing luggage goose spot"
18+
let password = "test_password"
19+
20+
let addressesCount = 101
21+
22+
guard let keystore = try BIP32Keystore(
23+
mnemonics: mnemonic,
24+
password: password,
25+
mnemonicsPassword: "",
26+
language: .english,
27+
prefixPath: HDNode.defaultPathMetamaskPrefix) else {
28+
XCTFail("Keystore has not generated")
29+
throw NSError(domain: "0", code: 0)
30+
}
31+
32+
let addresses = keystore.getAddressForAccount(password: password,
33+
preffixPath: HDNode.defaultPathMetamaskPrefix,
34+
number: addressesCount)
35+
XCTAssertEqual(addresses.count, addressesCount)
36+
XCTAssertNotEqual(addresses[11], addresses[1])
37+
38+
guard let sameKeystore = try BIP32Keystore(
39+
mnemonics: mnemonic,
40+
password: password,
41+
mnemonicsPassword: "",
42+
language: .english,
43+
prefixPath: HDNode.defaultPathMetamaskPrefix) else {
44+
XCTFail("Keystore has not generated")
45+
throw NSError(domain: "0", code: 0)
46+
}
47+
48+
let walletNumber = addressesCount - 1
49+
try sameKeystore.createNewCustomChildAccount(password: password,
50+
path: HDNode.defaultPathMetamaskPrefix + "/\(walletNumber)")
51+
let address = sameKeystore.addresses?.last?.address
52+
XCTAssertEqual(addresses.last?.address, address)
53+
}
54+
}

0 commit comments

Comments
 (0)