|
17 | 17 |
|
18 | 18 | package org.whispersystems.bithub.client; |
19 | 19 |
|
20 | | -import com.sun.jersey.api.client.Client; |
21 | | -import com.sun.jersey.api.client.ClientHandlerException; |
22 | | -import com.sun.jersey.api.client.UniformInterfaceException; |
23 | | -import com.sun.jersey.api.client.WebResource; |
24 | | -import com.sun.jersey.api.client.config.ClientConfig; |
25 | | -import com.sun.jersey.api.client.config.DefaultClientConfig; |
26 | | -import com.sun.jersey.api.json.JSONConfiguration; |
27 | | -import org.apache.commons.codec.binary.Hex; |
28 | | -import org.codehaus.jackson.map.ObjectMapper; |
| 20 | +import com.coinbase.api.Coinbase; |
| 21 | +import com.coinbase.api.CoinbaseBuilder; |
| 22 | +import com.coinbase.api.entity.Account; |
| 23 | +import com.coinbase.api.entity.Transaction; |
| 24 | +import com.coinbase.api.exception.CoinbaseException; |
| 25 | +import org.joda.money.Money; |
29 | 26 | import org.whispersystems.bithub.entities.Author; |
30 | | -import org.whispersystems.bithub.entities.BalanceResponse; |
31 | | -import org.whispersystems.bithub.entities.BitcoinTransaction; |
32 | | -import org.whispersystems.bithub.entities.BitcoinTransactionResponse; |
33 | | -import org.whispersystems.bithub.entities.CoinbaseTransaction; |
34 | | -import org.whispersystems.bithub.entities.CoinbseRecentTransactionsResponse; |
35 | | -import org.whispersystems.bithub.entities.ExchangeRate; |
36 | 27 |
|
37 | | -import javax.crypto.Mac; |
38 | | -import javax.crypto.spec.SecretKeySpec; |
39 | | -import javax.ws.rs.core.MediaType; |
40 | 28 | import java.io.IOException; |
41 | 29 | import java.math.BigDecimal; |
42 | | -import java.security.InvalidKeyException; |
43 | | -import java.security.NoSuchAlgorithmException; |
44 | 30 | import java.util.List; |
45 | 31 |
|
46 | 32 | /** |
|
50 | 36 | */ |
51 | 37 | public class CoinbaseClient { |
52 | 38 |
|
53 | | - private static final String COINBASE_URL = "https://coinbase.com"; |
54 | | - private static final String BALANCE_PATH = "/api/v1/account/balance"; |
55 | | - private static final String PAYMENT_PATH = "/api/v1/transactions/send_money"; |
56 | | - private static final String EXCHANGE_PATH = "/api/v1/currencies/exchange_rates"; |
57 | | - private static final String RECENT_TRANSACTIONS_PATH = "/api/v1/transactions"; |
58 | | - |
59 | | - private final String apiKey; |
60 | | - private final String apiSecret; |
61 | | - private final Client client; |
62 | | - |
63 | | - private static final ObjectMapper objectMapper = new ObjectMapper(); |
| 39 | + private final Coinbase coinbase; |
64 | 40 |
|
65 | 41 | public CoinbaseClient(String apiKey, String apiSecret) { |
66 | | - this.apiKey = apiKey; |
67 | | - this.apiSecret = apiSecret; |
68 | | - this.client = Client.create(getClientConfig()); |
| 42 | + this.coinbase = new CoinbaseBuilder().withApiKey(apiKey, apiSecret).build(); |
69 | 43 | } |
70 | 44 |
|
71 | | - public List<CoinbaseTransaction> getRecentTransactions() |
72 | | - throws IOException, TransferFailedException |
| 45 | + public List<Transaction> getRecentTransactions() |
| 46 | + throws CoinbaseException, IOException |
73 | 47 | { |
74 | | - try { |
75 | | - return getAuthenticatedWebResource(RECENT_TRANSACTIONS_PATH, null).get(CoinbseRecentTransactionsResponse.class) |
76 | | - .getTransactions(); |
77 | | - } catch (UniformInterfaceException | ClientHandlerException e) { |
78 | | - throw new IOException(e); |
79 | | - } |
| 48 | + return coinbase.getTransactions().getTransactions(); |
80 | 49 | } |
81 | 50 |
|
82 | | - public BigDecimal getExchangeRate() throws IOException { |
83 | | - try { |
84 | | - WebResource resource = client.resource(COINBASE_URL) |
85 | | - .path(EXCHANGE_PATH); |
86 | | - |
87 | | - String btcToUsd = resource.accept(MediaType.APPLICATION_JSON) |
88 | | - .get(ExchangeRate.class) |
89 | | - .getBtc_to_usd(); |
90 | | - |
91 | | - return new BigDecimal(btcToUsd); |
92 | | - } catch (UniformInterfaceException | ClientHandlerException e) { |
93 | | - throw new IOException(e); |
| 51 | + public BigDecimal getExchangeRate() throws IOException, CoinbaseException { |
| 52 | + return coinbase.getExchangeRates().get("btc_to_usd"); |
94 | 53 | } |
95 | | -} |
96 | 54 |
|
97 | 55 | public void sendPayment(Author author, BigDecimal amount, String url) |
98 | 56 | throws TransferFailedException |
99 | 57 | { |
100 | 58 | try { |
101 | 59 | String note = "Commit payment:\n__" + author.getUsername() + "__ " + url; |
102 | 60 |
|
103 | | - BitcoinTransaction transaction = new BitcoinTransaction(author.getEmail(), |
104 | | - amount.toPlainString(), |
105 | | - note); |
106 | | - |
107 | | - WebResource.Builder resource = getAuthenticatedWebResource(PAYMENT_PATH, transaction); |
| 61 | + Transaction transaction = new Transaction(); |
| 62 | + transaction.setTo(author.getEmail()); |
| 63 | + transaction.setAmount(Money.parse("BTC " + amount.toPlainString())); |
| 64 | + transaction.setNotes(note); |
108 | 65 |
|
109 | | - BitcoinTransactionResponse response = resource.type(MediaType.APPLICATION_JSON_TYPE) |
110 | | - .entity(transaction) |
111 | | - .post(BitcoinTransactionResponse.class); |
| 66 | + Transaction response = coinbase.sendMoney(transaction); |
112 | 67 |
|
113 | | - if (!response.isSuccess()) { |
| 68 | + if (response.getStatus() != Transaction.Status.COMPLETE) { |
114 | 69 | throw new TransferFailedException(); |
115 | 70 | } |
116 | | - |
117 | | - } catch (UniformInterfaceException | ClientHandlerException e) { |
| 71 | + } catch (CoinbaseException | IOException e) { |
118 | 72 | throw new TransferFailedException(e); |
119 | 73 | } |
120 | 74 | } |
121 | 75 |
|
122 | | - public BigDecimal getAccountBalance() throws IOException, TransferFailedException { |
123 | | - try { |
124 | | - WebResource.Builder resource = getAuthenticatedWebResource(BALANCE_PATH, null); |
125 | | - String amount = resource.get(BalanceResponse.class) |
126 | | - .getAmount(); |
127 | | - if (amount == null) { |
128 | | - throw new IOException("Empty amount in response!"); |
129 | | - } |
130 | | - |
131 | | - return new BigDecimal(amount); |
132 | | - } catch (UniformInterfaceException | ClientHandlerException e) { |
133 | | - throw new IOException(e); |
134 | | - } |
135 | | - } |
136 | | - |
137 | | - private WebResource.Builder getAuthenticatedWebResource(String path, Object body) throws TransferFailedException { |
138 | | - try { |
139 | | - String json = body == null ? "" : objectMapper.writeValueAsString(body); |
140 | | - String nonce = String.valueOf(System.currentTimeMillis()); |
141 | | - String message = nonce + COINBASE_URL + path + json; |
142 | | - Mac mac = Mac.getInstance("HmacSHA256"); |
143 | | - mac.init(new SecretKeySpec(apiSecret.getBytes(), "HmacSHA256")); |
| 76 | + public BigDecimal getAccountBalance() throws IOException, CoinbaseException { |
| 77 | + List<Account> accounts = coinbase.getAccounts().getAccounts(); |
| 78 | + Account primary = null; |
144 | 79 |
|
145 | | - String signature = new String(Hex.encodeHex(mac.doFinal(message.getBytes()))); |
146 | | - |
147 | | - return client.resource(COINBASE_URL) |
148 | | - .path(path) |
149 | | - .accept(MediaType.APPLICATION_JSON) |
150 | | - .header("ACCESS_SIGNATURE", signature) |
151 | | - .header("ACCESS_NONCE", nonce) |
152 | | - .header("ACCESS_KEY", apiKey); |
153 | | - } catch (NoSuchAlgorithmException | InvalidKeyException | IOException e) { |
154 | | - throw new TransferFailedException(); |
| 80 | + for (Account account : accounts) { |
| 81 | + if (account.isPrimary()) { |
| 82 | + primary = account; |
| 83 | + break; |
| 84 | + } |
155 | 85 | } |
156 | | - } |
157 | 86 |
|
158 | | - private ClientConfig getClientConfig() { |
159 | | - ClientConfig config = new DefaultClientConfig(); |
160 | | - config.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); |
161 | | - |
162 | | - return config; |
| 87 | + if (primary != null) return coinbase.getBalance(primary.getId()).getAmount(); |
| 88 | + else return new BigDecimal(0.0); |
163 | 89 | } |
164 | | - |
165 | 90 | } |
0 commit comments