/** * Get Market Info * * This is a combined call for {@link #getRate(CoinType, CoinType) getRate()} and * {@link #getLimit(CoinType, CoinType) getLimit()} API calls. */ public ShapeShiftMarketInfo getMarketInfo(CoinType typeFrom, CoinType typeTo) throws ShapeShiftException, IOException { return getMarketInfo(getPair(typeFrom, typeTo)); }
public ShapeShift getShapeShift() { if (shapeShift == null) { shapeShift = new ShapeShift(NetworkUtils.getHttpClient(getApplicationContext())); } return shapeShift; }
@Override protected Void doInBackground(Void... params) { if (application.isConnected()) { try { shapeShiftCoins = application.getShapeShift().getCoins(); } catch (Exception e) { error = e; } } else { error = new ShapeShiftException("No connection"); } return null; }
/** * Deposit Limit * * Gets the current deposit limit set by Shapeshift. Amounts deposited over this limit will be * sent to the return address if one was entered, otherwise the user will need to contact * ShapeShift support to retrieve their coins. This is an estimate because a sudden market swing * could move the limit. */ public ShapeShiftLimit getLimit(CoinType typeFrom, CoinType typeTo) throws ShapeShiftException, IOException { String pair = getPair(typeFrom, typeTo); String apiUrl = getApiUrl(String.format(LIMIT_API, pair)); Request request = new Request.Builder().url(apiUrl).build(); ShapeShiftLimit reply = new ShapeShiftLimit(getMakeApiCall(request)); if (!reply.isError) checkPair(pair, reply.pair); return reply; }
/** * Status of deposit to address * * This returns the status of the most recent deposit transaction to the address. */ public ShapeShiftTxStatus getTxStatus(AbstractAddress address) throws ShapeShiftException, IOException { String apiUrl = getApiUrl(String.format(TX_STATUS_API, address.toString())); Request request = new Request.Builder().url(apiUrl).build(); ShapeShiftTxStatus reply = new ShapeShiftTxStatus(getMakeApiCall(request)); if (!reply.isError && reply.address != null) checkAddress(address, reply.address); return new ShapeShiftTxStatus(reply, address); }
AbstractAddress refund) throws ShapeShiftException, IOException { String pair = getPair(refund.getType(), withdrawal.getType()); JSONObject requestJson = new JSONObject(); try { String apiUrl = getApiUrl(FIXED_AMOUNT_TX_API); RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, requestJson.toString()); Request request = new Request.Builder().url(apiUrl).post(body).build(); ShapeShiftAmountTx reply = new ShapeShiftAmountTx(getMakeApiCall(request)); if (!reply.isError) { checkPair(pair, reply.pair); checkValue(amount, reply.withdrawalAmount); checkAddress(withdrawal, reply.withdrawal);
ShapeShiftMarketInfo marketInfo = shapeShift.getMarketInfo( sourceType, sendToAddress.getType()); tradeWithdrawAddress == null || tradeWithdrawAmount == null) { ShapeShiftNormalTx normalTx = shapeShift.exchange(sendToAddress, refundAddress); tradeWithdrawAddress == null || tradeWithdrawAmount == null) { ShapeShiftAmountTx fixedAmountTx = shapeShift.exchangeForAmount(sendAmount, sendToAddress, refundAddress);
/** * Normal Transaction * * Make a normal exchange and receive with {@code withdrawal} address. The exchange pair is * determined from the {@link CoinType}s of {@code refund} and {@code withdrawal}. */ public ShapeShiftNormalTx exchange(AbstractAddress withdrawal, AbstractAddress refund) throws ShapeShiftException, IOException { JSONObject requestJson = new JSONObject(); try { requestJson.put("withdrawal", withdrawal.toString()); requestJson.put("pair", getPair(refund.getType(), withdrawal.getType())); requestJson.put("returnAddress", refund.toString()); if (apiPublicKey != null) requestJson.put("apiKey", apiPublicKey); } catch (JSONException e) { throw new ShapeShiftException("Could not create a JSON request", e); } String apiUrl = getApiUrl(NORMAL_TX_API); RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, requestJson.toString()); Request request = new Request.Builder().url(apiUrl).post(body).build(); ShapeShiftNormalTx reply = new ShapeShiftNormalTx(getMakeApiCall(request)); if (!reply.isError) checkAddress(withdrawal, reply.withdrawal); return reply; }
/** * Makes a call to ShapeShift about the market info of a pair. If case of a problem, it will * retry 3 times and return null if there was an error. * * Note: do not call this from the main thread! */ @Nullable public static ShapeShiftMarketInfo getMarketInfoSync(ShapeShift shapeShift, String pair) { // Try 3 times for (int tries = 1; tries <= 3; tries++) { try { log.info("Polling market info for pair: {}", pair); return shapeShift.getMarketInfo(pair); } catch (Exception e) { log.info("Will retry: {}", e.getMessage()); /* ignore and retry, with linear backoff */ try { Thread.sleep(1000 * tries); } catch (InterruptedException ie) { /*ignored*/ } } } return null; } }
@Test(expected = ShapeShiftException.class) public void testEmailFail() throws ShapeShiftException, IOException, InterruptedException, JSONException, AddressMalformedException { server.enqueue(new MockResponse().setBody(TX_STATUS_NO_DEPOSIT_JSON)); ShapeShiftTxStatus txStatusReply = shapeShift .getTxStatus(BTC.newAddress("1NDQPAGamGePkSZXW2CYBzXJEefB7N4bTN")); // Bad status shapeShift.requestEmailReceipt("mail@example.com", txStatusReply); }
/** * Get the current source and destination pair */ private String getPair() { return ShapeShift.getPair(sourceAccount.getCoinType(), destinationType); }
@Test(expected = ShapeShiftException.class) public void testFixedAmountTransactionFail3() throws ShapeShiftException, AddressMalformedException, IOException { server.enqueue(new MockResponse().setBody(FIXED_AMOUNT_TRANSACTION_JSON)); // Incorrect amount, correct is 1000 shapeShift.exchangeForAmount(DOGE.value("1"), DOGE.newAddress("DMHLQYG4j96V8cZX9WSuXxLs5RnZn6ibrV"), BTC.newAddress("1Nz4xHJjNCnZFPjRUq8CN4BZEXTgLZfeUW")); }
@Override public void run() { for (int tries = 3; tries > 0; tries--) { try { log.info("Polling status for deposit: {}", depositAddress); ShapeShiftTxStatus newStatus = shapeShift.getTxStatus(depositAddress); handler.sendMessage(handler.obtainMessage(UPDATE_SHAPESHIFT_STATUS, newStatus)); break; } catch (ShapeShiftException e) { log.warn("Error occurred while polling", e); handler.sendMessage(handler.obtainMessage(ERROR_MESSAGE, e.getMessage())); break; } catch (IOException e) { /* ignore and retry */ } } } }
@Test(expected = ShapeShiftException.class) public void testNormalTransactionFail() throws ShapeShiftException, AddressMalformedException, IOException { server.enqueue(new MockResponse().setBody(NORMAL_TRANSACTION_JSON)); // Incorrect Dogecoin address, correct is DMHLQYG4j96V8cZX9WSuXxLs5RnZn6ibrV shapeShift.exchange(DOGE.newAddress("DSntbp199h851m3Y1g3ruYCQHzWYCZQmmA"), BTC.newAddress("1Nz4xHJjNCnZFPjRUq8CN4BZEXTgLZfeUW")); }
/** * Makes a call to ShapeShift about the time left for the trade * * Note: do not call this from the main thread! */ @Nullable private static ShapeShiftTime getTimeLeftSync(ShapeShift shapeShift, AbstractAddress address) { // Try 3 times for (int tries = 1; tries <= 3; tries++) { try { log.info("Getting time left for: {}", address); return shapeShift.getTime(address); } catch (Exception e) { log.info("Will retry: {}", e.getMessage()); /* ignore and retry, with linear backoff */ try { Thread.sleep(1000 * tries); } catch (InterruptedException ie) { /*ignored*/ } } } return null; }
/** * Rate * * Gets the current rate offered by Shapeshift. This is an estimate because the rate can * occasionally change rapidly depending on the markets. The rate is also a 'use-able' rate not * a direct market rate. Meaning multiplying your input coin amount times the rate should give * you a close approximation of what will be sent out. This rate does not include the * transaction (miner) fee taken off every transaction. */ public ShapeShiftRate getRate(CoinType typeFrom, CoinType typeTo) throws ShapeShiftException, IOException { String pair = getPair(typeFrom, typeTo); String apiUrl = getApiUrl(String.format(RATE_API, pair)); Request request = new Request.Builder().url(apiUrl).build(); ShapeShiftRate reply = new ShapeShiftRate(getMakeApiCall(request)); if (!reply.isError) checkPair(pair, reply.pair); return reply; }
@Test(expected = ShapeShiftException.class) public void testGetMarketInfoFail() throws ShapeShiftException, IOException { server.enqueue(new MockResponse().setBody(MARKET_INFO_BTC_NBT_JSON)); // Incorrect pair shapeShift.getMarketInfo(BTC, LTC); }
@Test public void testEmail() throws ShapeShiftException, IOException, InterruptedException, JSONException, AddressMalformedException { // Schedule some responses. server.enqueue(new MockResponse().setBody(TX_STATUS_COMPLETE_JSON)); server.enqueue(new MockResponse().setBody(EMAIL_JSON)); ShapeShiftTxStatus txStatusReply = shapeShift.getTxStatus(BTC.newAddress("1NDQPAGamGePkSZXW2CYBzXJEefB7N4bTN")); ShapeShiftEmail emailReply = shapeShift.requestEmailReceipt("mail@example.com", txStatusReply); assertFalse(emailReply.isError); assertEquals(ShapeShiftEmail.Status.SUCCESS, emailReply.status); assertEquals("Email receipt sent", emailReply.message); // Optional: confirm that your app made the HTTP requests you were expecting. RecordedRequest request = server.takeRequest(); assertEquals("/txStat/1NDQPAGamGePkSZXW2CYBzXJEefB7N4bTN", request.getPath()); request = server.takeRequest(); assertEquals("/mail", request.getPath()); JSONObject reqJson = new JSONObject(request.getBody().readUtf8()); assertEquals("mail@example.com", reqJson.getString("email")); assertEquals("66fa0b4c11227f9f05efa13d23e58c65b50acbd6395a126b5cd751064e6e79df", reqJson.getString("txid")); }
public boolean isPair(CoinType sourceType, CoinType destinationType) { return isPair(ShapeShift.getPair(sourceType, destinationType)); }
@Test(expected = ShapeShiftException.class) public void testFixedAmountTransactionFail() throws ShapeShiftException, AddressMalformedException, IOException { server.enqueue(new MockResponse().setBody(FIXED_AMOUNT_TRANSACTION_JSON)); // We withdraw Dogecoins to a Bitcoin address shapeShift.exchangeForAmount(DOGE.value("1000"), BTC.newAddress("18ETaXCYhJ8sxurh41vpKC3E6Tu7oJ94q8"), BTC.newAddress("1Nz4xHJjNCnZFPjRUq8CN4BZEXTgLZfeUW")); }