package co.gem.round;
import com.google.common.base.Joiner;
import org.spongycastle.crypto.InvalidCipherTextException;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import co.gem.round.coinop.MultiWallet;
import co.gem.round.patchboard.Client;
import co.gem.round.patchboard.Resource;
/**
* Account class is the primary class where most of the interactions for the wallet will occur. From an account, you
* have the ability to send transactions, get balance and pending balance of the account, generate addresses.
*
* @author Julian Vergel de Dios (julian@gem.co) on 12/18/14.
*/
public class Account extends Base {
private Wallet wallet;
public Account(Resource resource, Round round) {
super(resource, round);
}
/**
* Getter for transactions on an account with the specified status
* @param status list of desired status to populate collection with
* @return TransactionCollection
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @see co.gem.round.Transaction.Status
*/
public TransactionCollection transactions(List<Transaction.Status> status) throws IOException, Client.UnexpectedStatusCodeException {
return transactions(null, status);
}
/**
* Getter for transactions on an account of the specified type
* @param type desired transaction type to populate collection with
* @return TransactionCollection
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @see co.gem.round.Transaction.Type
*/
public TransactionCollection transactions(Transaction.Type type) throws IOException, Client.UnexpectedStatusCodeException {
return transactions(type, null);
}
/**
* Getter for transactions on an account. Returns populated TransactionCollection object. To
* retrieve reference without fetching transactions use 'transactions(false)'
* @return TransactionCollection
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @see co.gem.round.TransactionCollection
*/
public TransactionCollection transactions() throws IOException, Client.UnexpectedStatusCodeException {
return transactions(null, null);
}
/**
* Getter for TransactionCollection object
* @param fetch boolean used to determine whether to populate collection
* @return TransactionCollection
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @see co.gem.round.TransactionCollection
*/
public TransactionCollection transactions(boolean fetch) throws IOException, Client.UnexpectedStatusCodeException {
return transactions(null, null, fetch);
}
/**
* Getter for the wallet this account belongs to
* @return Wallet
* @see co.gem.round.Wallet
*/
public Wallet getWallet() {
return wallet;
}
/**
* Getter for transactions on an account. Returns populated TransactionCollection object.
* @param type desired transaction type to populate collection with
* @param status list of desired status to populate collection with
* @return TransactionCollection
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @see co.gem.round.TransactionCollection
*/
public TransactionCollection transactions(Transaction.Type type, List<Transaction.Status> status)
throws IOException, Client.UnexpectedStatusCodeException {
return transactions(type, status, true);
}
/**
* Getter for transactions on an account.
* @param type desired transaction type
* @param status list of desired transaction status
* @param fetch boolean used to determine whether to populate collection
* @return TransactionCollection
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @see co.gem.round.TransactionCollection
*/
public TransactionCollection transactions(Transaction.Type type, List<Transaction.Status> status, boolean fetch)
throws IOException, Client.UnexpectedStatusCodeException {
Map<String, String> query = new HashMap<>();
if (type != null) {
query.put("type", type.toString());
}
if (status != null) {
query.put("status", Joiner.on(',').join(status));
}
Resource transactionsResource = resource.subresource("transactions", query);
TransactionCollection transactions = new TransactionCollection(transactionsResource, this.round);
if (fetch) {
transactions.fetch();
}
return transactions;
}
/**
* Getter for addresses within an account. Returns populated AddressCollection object. To
* retrieve reference without fetching addresses use 'addresses(false)'
* @return AddressCollection
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @see co.gem.round.AddressCollection
*/
public AddressCollection addresses()
throws IOException, Client.UnexpectedStatusCodeException {
return addresses(true);
}
/**
* Getter for AccountCollection object
* @param fetch boolean used to determine whether to populate collection
* @return AddressCollection
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @see co.gem.round.AddressCollection
*/
public AddressCollection addresses(boolean fetch)
throws IOException, Client.UnexpectedStatusCodeException {
Resource addressesResource = resource.subresource("addresses");
AddressCollection addresses = new AddressCollection(addressesResource, this.round);
if (fetch) {
addresses.fetch();
}
return addresses;
}
/**
* Getter for the name of the account
* @return String name
*/
public String name() {
return getString("name");
}
/**
* Getter for the balance of the account. This is 1 or more confirmations
* @return Long balance
*/
public long balance() {
return getLong("balance");
}
/**
* Getter for the pending balance on an account. This is 0 confirmations
* @return Long pending balance
*/
public long pendingBalance() {
return getLong("pending_balance");
}
/**
* Getter for the available balance on an account.
* @return Long available balance
*/
public long availableBalance() {
return getLong("available_balance");
}
public void setWallet(Wallet wallet) {
this.wallet = wallet;
}
@Deprecated
private Transaction payToEmail(String passphrase, String email, long amount)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, BadPaddingException, InvalidAlgorithmParameterException, InvalidCipherTextException, IllegalBlockSizeException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException {
return this.payToEmail(passphrase, email, amount, 6);
}
@Deprecated
public Transaction payToEmail(String passphrase, String email, long amount, int confirmations)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchProviderException, InvalidCipherTextException {
Recipient recipient = Recipient.recipientWithEmail(email, amount);
return this.pay(passphrase, recipient, confirmations);
}
/**
* Make a payment to a specific bitcoin address.
* @param passphrase String passphrase to the wallet
* @param address String valid bitcoin address based on the network
* @param amount Long amount in satoshis
* @return Payment signed payment
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public Transaction payToAddress(String passphrase, String address, long amount)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, NoSuchProviderException, InvalidCipherTextException {
return this.payToAddress(passphrase, address, amount, null, 6);
}
/**
* Make a payment to a specific bitcoin address.
* @param passphrase String passphrase to the wallet
* @param address String valid bitcoin address based on the network
* @param amount Long amount in satoshis
* @param redirectUri String used to override default mfa uri
* @return Payment signed payment
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public Transaction payToAddress(String passphrase, String address, long amount, String redirectUri)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, NoSuchProviderException, InvalidCipherTextException {
return this.payToAddress(passphrase, address, amount, redirectUri, 6);
}
/**
* Make a payment to a specific bitcoin address.
* @param passphrase String passphrase to the wallet
* @param address String valid bitcoin address based on the network
* @param amount Long amount in satoshis
* @param confirmations Int number of confirmations UTXOs must have to be used in the payment
* @return Payment signed payment
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public Transaction payToAddress(String passphrase, String address, long amount, int confirmations)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchProviderException, InvalidCipherTextException {
return this.pay(passphrase, Recipient.recipientWithAddress(address, amount), confirmations);
}
/**
*
* @param passphrase String passphrase to the wallet
* @param address String valid bitcoin address based on the network
* @param amount Long amount in satoshis
* @param redirectUri String used to override default mfa uri
* @param confirmations Int number of confirmations UTXOs must have to be used in the payment
* @return Payment signed payment
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public Transaction payToAddress(String passphrase, String address, long amount, String redirectUri, int confirmations)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchProviderException, InvalidCipherTextException {
return this.pay(passphrase, Recipient.recipientWithAddress(address, amount), redirectUri, confirmations);
}
/**
* Make a payment to a Recipient object with a default of 6 confirmations for UTXO selection
* @param passphrase String
* @param recipient Recipient
* @return Payment signed broadcasted payment object (transaction)
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @see co.gem.round.Recipient
*/
public Transaction pay(String passphrase, Recipient recipient)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchProviderException, InvalidCipherTextException {
List<Recipient> recipients = Arrays.asList(new Recipient[]{recipient});
return this.pay(passphrase, recipients, 6);
}
/**
*
* @param passphrase String passphrase to the wallet
* @param recipient Recipient
* @param redirectUri String used to override default mfa uri
* @return Payment signed broadcasted payment object (transaction)
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @see co.gem.round.Recipient
*/
public Transaction pay(String passphrase, Recipient recipient, String redirectUri)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchProviderException, InvalidCipherTextException {
List<Recipient> recipients = Arrays.asList(new Recipient[]{recipient});
return this.pay(passphrase, recipients, redirectUri, 6);
}
/**
* Make a payment to a Recipient object with an overrided number of confirmations for UTXO selection
* @param passphrase String
* @param recipient Recipient
* @param confirmations Int number of confirmations UTXOs must have for selection in the transaction
* @return Payment signed broadcasted payment object (transaction)
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @see co.gem.round.Recipient
*/
public Transaction pay(String passphrase, Recipient recipient, int confirmations)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchProviderException, InvalidCipherTextException {
List<Recipient> recipients = Arrays.asList(new Recipient[]{recipient});
return this.pay(passphrase, recipients, confirmations);
}
/**
*
* @param passphrase String passphrase to the wallet
* @param recipient Recipient
* @param redirectUri String used to override default mfa uri
* @param confirmations Int number of confirmations UTXOs must have to be used in the payment
* @return Payment signed broadcasted payment object (transaction)
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @see co.gem.round.Recipient
*/
public Transaction pay(String passphrase, Recipient recipient, String redirectUri, int confirmations)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchProviderException, InvalidCipherTextException {
List<Recipient> recipients = Arrays.asList(new Recipient[]{recipient});
return this.pay(passphrase, recipients, redirectUri, confirmations);
}
/**
* Make payment to a list of recipients. This is a transaction with multiple To: addresses and amounts
* @param passphrase String
* @param recipients List of recipients
* @return Signed broadcasted payment
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @see co.gem.round.Recipient
*/
public Transaction pay(String passphrase, List<Recipient> recipients)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchProviderException, InvalidCipherTextException {
return this.pay(passphrase, recipients, 6);
}
/**
*
* @param passphrase String passphrase to the wallet
* @param recipients List of recipients
* @param redirectUri String used to override default mfa uri
* @return Signed broadcasted payment
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @see co.gem.round.Recipient
*/
public Transaction pay(String passphrase, List<Recipient> recipients, String redirectUri)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchProviderException, InvalidCipherTextException {
return this.pay(passphrase, recipients, redirectUri, 6);
}
/**
* Make payment to a list of recipients. This is a transaction with multiple To: addresses and amounts
* @param passphrase String
* @param recipients List of recipients
* @param confirmations Int number of confirmations UTXOs must have for selection in the transaction
* @return Signed broadcasted payment
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @see co.gem.round.Recipient
*/
public Transaction pay(String passphrase, List<Recipient> recipients, int confirmations)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException,
BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, NoSuchProviderException, InvalidCipherTextException {
return this.pay(passphrase,recipients,null,confirmations);
}
/**
*
* @param passphrase String passphrase to the wallet
* @param recipients List of recipients
* @param redirectUri String used to override default mfa uri
* @param confirmations Int number of confirmations UTXOs must have for selection in the transaction
* @return Signed broadcasted payment
* @throws IOException
* @throws Client.UnexpectedStatusCodeException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @see co.gem.round.Recipient
*/
public Transaction pay(String passphrase, List<Recipient> recipients, String redirectUri, int confirmations)
throws IOException, Client.UnexpectedStatusCodeException,
NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException,
BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, NoSuchProviderException, InvalidCipherTextException {
final Transaction payment = this.transactions(false).create(recipients, confirmations);
this.wallet.unlock(passphrase, new UnlockedWalletCallback() {
@Override
public void execute(MultiWallet wallet) throws IOException, Client.UnexpectedStatusCodeException {
payment.sign(wallet);
}
});
if (redirectUri != null) {
payment.setRedirectUri(redirectUri);
}
if (wallet.hasApplication()) {
payment.approve();
}
return payment;
}
}