137 lines
5.4 KiB
Java
137 lines
5.4 KiB
Java
package io.rudefox.cold;
|
|
|
|
import com.bjdweck.bitcoin.address.BitcoinAddress;
|
|
import com.bjdweck.bitcoin.extendedkey.AddressChain;
|
|
import com.bjdweck.bitcoin.extendedkey.DerivationPath;
|
|
import com.bjdweck.bitcoin.extendedkey.KeyOrigin;
|
|
import com.bjdweck.bitcoin.extendedkey.PrivateExtendedKey;
|
|
import com.bjdweck.bitcoin.hdwallet.Bip44Purpose;
|
|
import com.bjdweck.bitcoin.hdwallet.Bip44SigningAccount;
|
|
import com.bjdweck.bitcoin.hdwallet.Bip44Wallet;
|
|
import com.bjdweck.bitcoin.mnemonic.Mnemonic;
|
|
import com.bjdweck.bitcoin.mnemonic.Seed;
|
|
import com.bjdweck.bitcoin.psbt.Psbt;
|
|
import com.bjdweck.bitcoin.transaction.scriptpubkey.ScriptPubKey;
|
|
import picocli.CommandLine;
|
|
|
|
@SuppressWarnings("ALL")
|
|
@CommandLine.Command(name = "wallet", description = "BIP44 wallet operations")
|
|
public class WalletCommand implements Runnable {
|
|
|
|
@CommandLine.ParentCommand
|
|
private RudefoxCold globalOptions;
|
|
|
|
@CommandLine.Option(names = {"-s", "--sentence"}, description = "mnemonic sentence", required = true)
|
|
String sentence;
|
|
|
|
@CommandLine.Option(names = {"-p", "--passphrase"}, description = "optional mnemonic passphrase")
|
|
String passphrase;
|
|
|
|
Bip44Wallet getWallet() {
|
|
Seed seed = Mnemonic.fromSentence(sentence).generateSeed(passphrase);
|
|
return new Bip44Wallet(PrivateExtendedKey.fromSeed(seed), globalOptions.getNetworkParameters());
|
|
}
|
|
|
|
Bip44SigningAccount getAccount(Bip44Purpose purpose, int accountSeq) {
|
|
return getWallet().deriveAccount(purpose, accountSeq);
|
|
}
|
|
|
|
@CommandLine.Command(name = "listxpub", description = "list xpub (default: SLIP-0132)")
|
|
public int listXpub(
|
|
|
|
@CommandLine.Option(names = {"-q", "--qrcode"}, description = "output QR code")
|
|
boolean isQRCode,
|
|
|
|
@CommandLine.Option(names = {"-p", "--purpose"}, description = "purpose",
|
|
paramLabel = "[P2PKH, P2SH_P2WPKH, P2WPKH, P2SH_MultiSigP2WSH, MultiSigP2WSH]",
|
|
defaultValue = "P2PKH")
|
|
Bip44Purpose purpose,
|
|
|
|
@CommandLine.Option(names = {"-a", "--account"}, description = "account sequence number",
|
|
paramLabel = "n", defaultValue = "0")
|
|
int accountSeq) {
|
|
|
|
Bip44SigningAccount bip44SigningAccount = getAccount(purpose, accountSeq);
|
|
String slip0132 = bip44SigningAccount.toXpubSlip0132Base58();
|
|
String keyOrigin = bip44SigningAccount.getKeyOrigin().toString();
|
|
|
|
if (isQRCode) {
|
|
System.out.println(QRCode.toQRCode(slip0132));
|
|
return 0;
|
|
}
|
|
|
|
System.out.printf("[%s]%s%n", keyOrigin, slip0132);
|
|
return 0;
|
|
}
|
|
|
|
@CommandLine.Command(name = "listaddress", description = "list account addresses")
|
|
public int listAddress(
|
|
|
|
@CommandLine.Option(names = {"-p", "--purpose"}, description = "purpose",
|
|
paramLabel = "[P2PKH, P2SH_P2WPKH, P2WPKH, P2SH_MultiSigP2WSH, MultiSigP2WSH]",
|
|
defaultValue = "P2PKH")
|
|
Bip44Purpose purpose,
|
|
|
|
@CommandLine.Option(names = {"-a", "--account"}, description = "account sequence number",
|
|
paramLabel = "<n>", defaultValue = "0")
|
|
int accountSeq,
|
|
|
|
@CommandLine.Option(names = {"-c", "--address-chain"}, description = "address chain",
|
|
paramLabel = "[INTERNAL|EXTERNAL]", defaultValue = "EXTERNAL")
|
|
AddressChain addressChain,
|
|
|
|
@CommandLine.Option(names = {"-s", "--address-seq"}, description = "starting address sequence number",
|
|
paramLabel = "<n>", defaultValue = "0")
|
|
int addressSeq,
|
|
|
|
@CommandLine.Option(names = {"-n", "--count"}, description = "number of addresses to list",
|
|
paramLabel = "<n>", defaultValue = "10")
|
|
int count) {
|
|
|
|
Bip44SigningAccount account = getAccount(purpose, accountSeq);
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
int seq = addressSeq + i;
|
|
|
|
DerivationPath addressPath = DerivationPath.m().slash(addressChain.getSequence()).slash(seq);
|
|
KeyOrigin keyOrigin = account.getKeyOrigin().combineRelativePath(addressPath);
|
|
|
|
ScriptPubKey scriptPubKey = account.deriveScriptPubKey(addressChain, seq);
|
|
BitcoinAddress address = scriptPubKey.getAddress(globalOptions.getNetworkParameters());
|
|
|
|
System.out.printf("%s: %s%n", keyOrigin, address);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
@CommandLine.Command(name = "signpsbt", description = "sign a PSBT")
|
|
public int signPsbt(
|
|
@CommandLine.Parameters()
|
|
String psbtBase64) {
|
|
|
|
Psbt psbt = Psbt.fromBase64(psbtBase64);
|
|
|
|
psbt.getValidationViolationMap();
|
|
/*
|
|
Satoshi fee = psbt.getFee();
|
|
Satoshi spendAmount = psbt.getSpendAmount(getWallet());
|
|
BitcoinAddress spendAddress = psbt.getSpendAddress(getWallet());
|
|
|
|
System.out.printf("Confirm spend of %s to %s with a fee of %s", spendAmount.toBitcoinString(), spendAddress.getAddressString(), fee.toBitcoinString());
|
|
*/
|
|
psbt.signPsbt(getWallet());
|
|
|
|
System.out.println(psbt.toBase64());
|
|
|
|
return 0;
|
|
}
|
|
|
|
@CommandLine.Spec
|
|
CommandLine.Model.CommandSpec commandSpec;
|
|
|
|
public void run() {
|
|
throw new CommandLine.ParameterException(commandSpec.commandLine(), "Missing required wallet subcommand");
|
|
}
|
|
} |