Pantani/pool-party

Multi-coin address pool generation for bip44.

★ 2Forks 1GoGitHub ↗Compare
address-poolbip39bip44bitcoinethereumhdhdwalletwallet

README

Pool Party

Go Reference codecov

Pool Party is a Go library for generating deterministic BIP39/BIP44 address pools for multiple coins.

Status

This branch modernizes the project for current Go toolchains:

  • Go module target: go 1.26.4
  • Standard BIP32 derivation via hdkeychain.Derive
  • BIP39 seed normalization with UTF-8 NFKD
  • Public address-only API that does not expose private keys
  • Tests for deterministic vectors, invalid ranges, global network mutation, secret redaction, and public address generation

See CHANGELOG.md before upgrading an existing wallet flow. This pass changes BIP32 derivation to the current standard behavior and normalizes BIP39 seed inputs with Unicode NFKD.

Install

go get github.com/Pantani/pool-party

Safe Address-Only Usage

Use GeneratePublicAddressPool when you only need public addresses. It returns no private key, WIF, extended key, master key, seed, mnemonic, or passphrase fields.

package main

import (
	"fmt"
	"log"

	poolparty "github.com/Pantani/pool-party"
	"github.com/Pantani/pool-party/bip44"
)

func main() {
	pool := poolparty.NewPoolWithSecret(
		bip44.Ethereum,
		"rent slogan lemon nerve soup annual depend shift olympic similar bounce wait often fury slush fish crazy bring police level economy crush can energy",
		"",
	)

	addresses, err := pool.GeneratePublicAddressPool(0, 3)
	if err != nil {
		log.Fatal(err)
	}

	for _, address := range addresses {
		fmt.Printf("%d %s\n", address.Index, address.Address)
	}
}

Exporting Private Keys

GeneratePrivateAddressPool and bip44.GeneratePrivateWallets return private key material. Use them only when you explicitly need exportable private keys.

addresses, err := pool.GeneratePrivateAddressPool(0, 1)
if err != nil {
	log.Fatal(err)
}

fmt.Println(addresses[0].Address)
fmt.Println(addresses[0].Privkey) // secret: store and log with care

Do not log mnemonics, passphrases, private keys, WIF strings, xprv values, or full wallet/account structs. Pool.String redacts mnemonic and passphrase, but callers should still treat the object as sensitive.

Generating A Mnemonic

pool := poolparty.NewPool(bip44.Bitcoin)

if err := pool.GenerateMnemonic(256, "optional-passphrase"); err != nil {
	log.Fatal(err)
}

addresses, err := pool.GeneratePublicAddressPool(0, 10)
if err != nil {
	log.Fatal(err)
}

fmt.Println(addresses[0].Address)

Supported Coins

  • Ethereum
  • Energi
  • Bitcoin
  • Litecoin
  • Dash
  • Dogecoin

Derivation Notes

Pool Party derives receive addresses with:

m/44'/coin_type'/0'/0/index

The modernized implementation uses github.com/btcsuite/btcd/btcutil/hdkeychain.ExtendedKey.Derive, which follows the standard BIP32 behavior. Older btcsuite Child behavior was renamed upstream to DeriveNonStandard because it was affected by btcsuite issue #172. This means some address vectors can differ from old Pool Party releases that used Child.

Seed Normalization And Legacy Recovery

bip39.NewSeed normalizes both the mnemonic and optional password with Unicode NFKD before PBKDF2, matching BIP39. This is the right path for new wallets.

Older Pool Party releases did not normalize these inputs. Users with only ASCII mnemonics and passphrases are unaffected because ASCII is unchanged by NFKD. Users who created wallets with non-ASCII characters, such as accents or combining marks, should try both derivation paths during recovery:

standardSeed := bip39.NewSeed(mnemonic, passphrase)
legacySeed := bip39.NewSeedLegacy(mnemonic, passphrase)

Use the seed that reproduces the known address history, then migrate operational tooling to NewSeed for new wallets.

Custom BIP39 Word Lists

bip39.SetWordList accepts only well-formed BIP39 word lists: exactly 2048 unique non-empty words. It returns bip39.ErrWordListInvalid and leaves the active word list unchanged when validation fails.

Development

go test -mod=readonly ./...
go vet ./...
go list -m -u all

Use rtk before commands in this workspace:

rtk go test -mod=readonly ./...
rtk go vet ./...

Security Scope

This library performs deterministic key derivation locally. It does not encrypt secrets, manage secure storage, wipe memory, or broadcast transactions. Applications using it are responsible for secure mnemonic/private-key lifecycle management.

See docs/AUDIT.md and docs/MODERNIZATION_PLAN.md for the current audit and maintenance plan.

Contributors

Pantani

Issues