mirror of
https://github.com/sparrowwallet/drongo.git
synced 2024-12-27 10:36:45 +00:00
wallet receiving and change support
This commit is contained in:
parent
c871bf829a
commit
eabcf4e8f4
3 changed files with 131 additions and 6 deletions
|
@ -1,15 +1,27 @@
|
||||||
package com.sparrowwallet.drongo;
|
package com.sparrowwallet.drongo;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.crypto.ChildNumber;
|
||||||
|
|
||||||
public enum KeyPurpose {
|
public enum KeyPurpose {
|
||||||
RECEIVE(0), CHANGE(1);
|
RECEIVE(ChildNumber.ZERO), CHANGE(ChildNumber.ONE);
|
||||||
|
|
||||||
private final int pathIndex;
|
private final ChildNumber pathIndex;
|
||||||
|
|
||||||
KeyPurpose(int pathIndex) {
|
KeyPurpose(ChildNumber pathIndex) {
|
||||||
this.pathIndex = pathIndex;
|
this.pathIndex = pathIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPathIndex() {
|
public ChildNumber getPathIndex() {
|
||||||
return pathIndex;
|
return pathIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static KeyPurpose fromChildNumber(ChildNumber childNumber) {
|
||||||
|
for(KeyPurpose keyPurpose : values()) {
|
||||||
|
if(keyPurpose.getPathIndex().equals(childNumber)) {
|
||||||
|
return keyPurpose;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,12 +105,12 @@ public class Keystore {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeterministicKey getKey(KeyPurpose keyPurpose, int keyIndex) {
|
public DeterministicKey getKey(KeyPurpose keyPurpose, int keyIndex) {
|
||||||
List<ChildNumber> receivingDerivation = List.of(extendedPublicKey.getKeyChildNumber(), new ChildNumber(keyPurpose.getPathIndex()), new ChildNumber(keyIndex));
|
List<ChildNumber> receivingDerivation = List.of(extendedPublicKey.getKeyChildNumber(), keyPurpose.getPathIndex(), new ChildNumber(keyIndex));
|
||||||
return extendedPublicKey.getKey(receivingDerivation);
|
return extendedPublicKey.getKey(receivingDerivation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyDerivation getDerivation(KeyPurpose keyPurpose, int keyIndex) {
|
public KeyDerivation getDerivation(KeyPurpose keyPurpose, int keyIndex) {
|
||||||
return getKeyDerivation().extend(new ChildNumber(keyPurpose.getPathIndex())).extend(new ChildNumber(keyIndex));
|
return getKeyDerivation().extend(keyPurpose.getPathIndex()).extend(new ChildNumber(keyIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package com.sparrowwallet.drongo.wallet;
|
package com.sparrowwallet.drongo.wallet;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.KeyDerivation;
|
||||||
import com.sparrowwallet.drongo.KeyPurpose;
|
import com.sparrowwallet.drongo.KeyPurpose;
|
||||||
import com.sparrowwallet.drongo.address.Address;
|
import com.sparrowwallet.drongo.address.Address;
|
||||||
|
import com.sparrowwallet.drongo.crypto.ChildNumber;
|
||||||
import com.sparrowwallet.drongo.crypto.DeterministicKey;
|
import com.sparrowwallet.drongo.crypto.DeterministicKey;
|
||||||
import com.sparrowwallet.drongo.crypto.ECKey;
|
import com.sparrowwallet.drongo.crypto.ECKey;
|
||||||
import com.sparrowwallet.drongo.crypto.Key;
|
import com.sparrowwallet.drongo.crypto.Key;
|
||||||
|
@ -14,12 +16,14 @@ import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class Wallet {
|
public class Wallet {
|
||||||
|
private static final int DEFAULT_LOOKAHEAD = 20;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private PolicyType policyType;
|
private PolicyType policyType;
|
||||||
private ScriptType scriptType;
|
private ScriptType scriptType;
|
||||||
private Policy defaultPolicy;
|
private Policy defaultPolicy;
|
||||||
private List<Keystore> keystores = new ArrayList<>();
|
private List<Keystore> keystores = new ArrayList<>();
|
||||||
|
private final List<Node> accountNodes = new ArrayList<>();
|
||||||
|
|
||||||
public Wallet() {
|
public Wallet() {
|
||||||
}
|
}
|
||||||
|
@ -76,6 +80,25 @@ public class Wallet {
|
||||||
this.keystores = keystores;
|
this.keystores = keystores;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Node getNodes(KeyPurpose keyPurpose) {
|
||||||
|
Node purposeNode;
|
||||||
|
Optional<Node> optionalPurposeNode = accountNodes.stream().filter(node -> node.getKeyPurpose().equals(keyPurpose)).findFirst();
|
||||||
|
if(optionalPurposeNode.isEmpty()) {
|
||||||
|
purposeNode = new Node(keyPurpose);
|
||||||
|
accountNodes.add(purposeNode);
|
||||||
|
} else {
|
||||||
|
purposeNode = optionalPurposeNode.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
purposeNode.fillToLookAhead(getLookAhead());
|
||||||
|
return purposeNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLookAhead() {
|
||||||
|
//TODO: Calculate using seen transactions
|
||||||
|
return DEFAULT_LOOKAHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
public Address getAddress(KeyPurpose keyPurpose, int index) {
|
public Address getAddress(KeyPurpose keyPurpose, int index) {
|
||||||
if(policyType == PolicyType.SINGLE) {
|
if(policyType == PolicyType.SINGLE) {
|
||||||
Keystore keystore = getKeystores().get(0);
|
Keystore keystore = getKeystores().get(0);
|
||||||
|
@ -255,4 +278,94 @@ public class Wallet {
|
||||||
keystore.clearPrivate();
|
keystore.clearPrivate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class Node {
|
||||||
|
private final String derivationPath;
|
||||||
|
private String label;
|
||||||
|
private Long amount;
|
||||||
|
private final List<Node> children = new ArrayList<>();
|
||||||
|
|
||||||
|
private final transient KeyPurpose keyPurpose;
|
||||||
|
private final transient int index;
|
||||||
|
private final transient List<ChildNumber> derivation;
|
||||||
|
|
||||||
|
public Node(String derivationPath) {
|
||||||
|
this.derivationPath = derivationPath;
|
||||||
|
this.derivation = KeyDerivation.parsePath(derivationPath);
|
||||||
|
this.keyPurpose = KeyPurpose.fromChildNumber(derivation.get(0));
|
||||||
|
this.index = derivation.get(derivation.size() - 1).num();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node(KeyPurpose keyPurpose) {
|
||||||
|
this.derivation = List.of(keyPurpose.getPathIndex());
|
||||||
|
this.derivationPath = KeyDerivation.writePath(derivation);
|
||||||
|
this.keyPurpose = keyPurpose;
|
||||||
|
this.index = keyPurpose.getPathIndex().num();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node(KeyPurpose keyPurpose, int index) {
|
||||||
|
this.derivation = List.of(keyPurpose.getPathIndex(), new ChildNumber(index));
|
||||||
|
this.derivationPath = KeyDerivation.writePath(derivation);
|
||||||
|
this.keyPurpose = keyPurpose;
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyPurpose getKeyPurpose() {
|
||||||
|
return keyPurpose;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabel(String label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(Long amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Node> getChildren() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address getAddress() {
|
||||||
|
return Wallet.this.getAddress(keyPurpose, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Script getOutputScript() {
|
||||||
|
return Wallet.this.getOutputScript(keyPurpose, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillToLookAhead(int lookAhead) {
|
||||||
|
for(int i = 0; i < lookAhead; i++) {
|
||||||
|
Node node = new Node(getKeyPurpose(), i);
|
||||||
|
if(!getChildren().contains(node)) {
|
||||||
|
getChildren().add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Node node = (Node) o;
|
||||||
|
return derivationPath.equals(node.derivationPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(derivationPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue