tech.figure.hdwallet.bip44.Paths.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hdwallet-bip44 Show documentation
Show all versions of hdwallet-bip44 Show documentation
A collection of libraries to facilitate HDWallet usage
The newest version!
package tech.figure.hdwallet.bip44
const val BIP44_HARDENING_FLAG = 0x80000000.toInt()
object PathElements {
/**
* Given a BIP-32 style path like "m/44'/1'/0'/420'", generate a list of [PathElement] represented the parsed path.
*
* @param path The BIP-32 style derivation path to parse.
* @return The parsed path as a list of [PathElement] instances.
*/
fun from(path: String): List = path.parseBIP44Path()
}
// test: m/44'/1'/0'/0/0'
// prod: m/44'/505'/0'/0/0
internal fun String.parseBIP44Path(): List {
val s = split("/")
require(s[0] == "m") { "No root account m/" }
require(s.size <= 6) { "bip44 path too deep" }
return s.drop(1).mapIndexed { position, part ->
val l = part.takeWhile { c -> c.isDigit() }
val n = l.toInt()
val r = part.substring(l.length, part.length)
val hard = r == "\'" || r.lowercase() == "h"
require(r.isEmpty() || hard) { "Invalid hardening: $r" }
buildPathElement(position, n, hard)
}
}
internal fun List.toPathString() =
(listOf("m") + map { it.toString() }).joinToString("/")
internal fun buildPathElement(position: Int, n: Int, hard: Boolean): PathElement =
when (position) {
0 -> PathElement.Purpose(n, hard)
1 -> PathElement.CoinType(n, hard)
2 -> PathElement.Account(n, hard)
3 -> PathElement.Change(n, hard)
4 -> PathElement.Index(n, hard)
else -> error("Invalid path position: $position")
}
/**
* Represents the individual elements of a BIP44-style derivation path, providing
* typed representations of the components of the derivation path.
*
* See https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
*/
sealed class PathElement(open val number: Int, open val hardened: Boolean) {
private fun Boolean.into(t: R, f: R): R = if (this) t else f
val hardenedNumber: Int get() = if (hardened) number or BIP44_HARDENING_FLAG else number
override fun toString(): String = "$number${hardened.into("'", "")}"
data class Purpose(override val number: Int, override val hardened: Boolean) : PathElement(number, hardened) {
override fun toString(): String = super.toString()
}
data class CoinType(override val number: Int, override val hardened: Boolean) : PathElement(number, hardened) {
override fun toString(): String = super.toString()
}
data class Account(override val number: Int, override val hardened: Boolean) : PathElement(number, hardened) {
override fun toString(): String = super.toString()
}
data class Change(override val number: Int, override val hardened: Boolean) : PathElement(number, hardened) {
override fun toString(): String = super.toString()
}
data class Index(override val number: Int, override val hardened: Boolean) : PathElement(number, hardened) {
override fun toString(): String = super.toString()
}
}