replace xmr.to with SideShift.ai (#710)
replace xmr.to with SideShift.ai random bugfixes upgrade gradle & dependenciesmerge-requests/3/head
parent
ab6069058b
commit
57ddddfce2
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.service.shift;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ShiftError {
|
||||
@Getter
|
||||
private final Error errorType;
|
||||
@Getter
|
||||
private final String errorMsg;
|
||||
|
||||
public enum Error {
|
||||
SERVICE,
|
||||
INFRASTRUCTURE
|
||||
}
|
||||
|
||||
public boolean isRetryable() {
|
||||
return errorType == Error.INFRASTRUCTURE;
|
||||
}
|
||||
|
||||
public ShiftError(final JSONObject jsonObject) throws JSONException {
|
||||
final JSONObject errorObject = jsonObject.getJSONObject("error");
|
||||
errorType = Error.SERVICE;
|
||||
errorMsg = errorObject.getString("message");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String toString() {
|
||||
return getErrorMsg();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.service.shift;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ShiftException extends Exception {
|
||||
@Getter
|
||||
private final int code;
|
||||
@Getter
|
||||
private final ShiftError error;
|
||||
|
||||
public ShiftException(int code) {
|
||||
this.code = code;
|
||||
this.error = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.service.shift.sideshift.api;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public interface CreateOrder {
|
||||
String TAG = "side";
|
||||
|
||||
double getBtcAmount();
|
||||
|
||||
String getBtcAddress();
|
||||
|
||||
String getQuoteId();
|
||||
|
||||
String getOrderId();
|
||||
|
||||
double getXmrAmount();
|
||||
|
||||
String getXmrAddress();
|
||||
|
||||
Date getCreatedAt(); // createdAt
|
||||
|
||||
Date getExpiresAt(); // expiresAt
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.service.shift.sideshift.api;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public interface RequestQuote {
|
||||
|
||||
double getBtcAmount(); // settleAmount
|
||||
|
||||
String getId(); // id
|
||||
|
||||
Date getCreatedAt(); // createdAt
|
||||
|
||||
Date getExpiresAt(); // expiresAt
|
||||
|
||||
double getXmrAmount(); // depositAmount
|
||||
|
||||
double getPrice(); // rate
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.service.shift.sideshift.api;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.m2049r.xmrwallet.service.shift.ShiftCallback;
|
||||
|
||||
public interface SideShiftApi {
|
||||
|
||||
String ASSET = "btc";
|
||||
int QUERY_INTERVAL = 5000; // ms
|
||||
|
||||
/**
|
||||
* Queries the order parameter.
|
||||
*
|
||||
* @param callback the callback with the OrderParameter object
|
||||
*/
|
||||
void queryOrderParameters(@NonNull final ShiftCallback<QueryOrderParameters> callback);
|
||||
|
||||
/**
|
||||
* Creates an order
|
||||
*
|
||||
* @param xmrAmount the desired XMR amount
|
||||
*/
|
||||
void requestQuote(final double xmrAmount, @NonNull final ShiftCallback<RequestQuote> callback);
|
||||
|
||||
/**
|
||||
* Creates an order
|
||||
*
|
||||
* @param quoteId the desired XMR amount
|
||||
* @param btcAddress the target bitcoin address
|
||||
*/
|
||||
void createOrder(final String quoteId, @NonNull final String btcAddress, @NonNull final ShiftCallback<CreateOrder> callback);
|
||||
|
||||
/**
|
||||
* Queries the order status for given current order
|
||||
*
|
||||
* @param orderId the order ID
|
||||
* @param callback the callback with the OrderStatus object
|
||||
*/
|
||||
void queryOrderStatus(@NonNull final String orderId, @NonNull final ShiftCallback<QueryOrderStatus> callback);
|
||||
|
||||
/*
|
||||
* Returns the URL for manually querying the order status
|
||||
*
|
||||
* @param orderId the order ID
|
||||
*/
|
||||
Uri getQueryOrderUri(String orderId);
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.service.shift.sideshift.network;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.m2049r.xmrwallet.BuildConfig;
|
||||
import com.m2049r.xmrwallet.service.shift.NetworkCallback;
|
||||
import com.m2049r.xmrwallet.service.shift.ShiftApiCall;
|
||||
import com.m2049r.xmrwallet.service.shift.ShiftCallback;
|
||||
import com.m2049r.xmrwallet.service.shift.sideshift.api.CreateOrder;
|
||||
import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
|
||||
import com.m2049r.xmrwallet.util.DateHelper;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
class CreateOrderImpl implements CreateOrder {
|
||||
@Getter
|
||||
private final double btcAmount;
|
||||
@Getter
|
||||
private final String btcAddress;
|
||||
@Getter
|
||||
private final String quoteId;
|
||||
@Getter
|
||||
private final String orderId;
|
||||
@Getter
|
||||
private final double xmrAmount;
|
||||
@Getter
|
||||
private final String xmrAddress;
|
||||
@Getter
|
||||
private final Date createdAt;
|
||||
@Getter
|
||||
private final Date expiresAt;
|
||||
|
||||
CreateOrderImpl(final JSONObject jsonObject) throws JSONException {
|
||||
// sanity checks
|
||||
final String depositMethod = jsonObject.getString("depositMethodId");
|
||||
final String settleMethod = jsonObject.getString("settleMethodId");
|
||||
if (!"xmr".equals(depositMethod) || !SideShiftApi.ASSET.equals(settleMethod))
|
||||
throw new IllegalStateException();
|
||||
|
||||
btcAmount = jsonObject.getDouble("settleAmount");
|
||||
JSONObject settleAddress = jsonObject.getJSONObject("settleAddress");
|
||||
btcAddress = settleAddress.getString("address");
|
||||
|
||||
xmrAmount = jsonObject.getDouble("depositAmount");
|
||||
JSONObject depositAddress = jsonObject.getJSONObject("depositAddress");
|
||||
xmrAddress = depositAddress.getString("address");
|
||||
|
||||
quoteId = jsonObject.getString("quoteId");
|
||||
|
||||
orderId = jsonObject.getString("orderId");
|
||||
|
||||
try {
|
||||
final String created = jsonObject.getString("createdAtISO");
|
||||
createdAt = DateHelper.parse(created);
|
||||
final String expires = jsonObject.getString("expiresAtISO");
|
||||
expiresAt = DateHelper.parse(expires);
|
||||
} catch (ParseException ex) {
|
||||
throw new JSONException(ex.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void call(@NonNull final ShiftApiCall api, final String quoteId, @NonNull final String btcAddress,
|
||||
@NonNull final ShiftCallback<CreateOrder> callback) {
|
||||
try {
|
||||
final JSONObject request = createRequest(quoteId, btcAddress);
|
||||
api.call("orders", request, new NetworkCallback() {
|
||||
@Override
|
||||
public void onSuccess(JSONObject jsonObject) {
|
||||
try {
|
||||
callback.onSuccess(new CreateOrderImpl(jsonObject));
|
||||
} catch (JSONException ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
});
|
||||
} catch (JSONException ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static JSONObject createRequest(final String quoteId, final String address) throws JSONException {
|
||||
final JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("type", "fixed");
|
||||
jsonObject.put("quoteId", quoteId);
|
||||
jsonObject.put("settleAddress", address);
|
||||
if (!BuildConfig.ID_A.isEmpty() && !"null".equals(BuildConfig.ID_A)) {
|
||||
jsonObject.put("affiliateId", BuildConfig.ID_A);
|
||||
}
|
||||
return jsonObject;
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.service.shift.sideshift.network;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.m2049r.xmrwallet.service.shift.NetworkCallback;
|
||||
import com.m2049r.xmrwallet.service.shift.ShiftApiCall;
|
||||
import com.m2049r.xmrwallet.util.DateHelper;
|
||||
import com.m2049r.xmrwallet.service.shift.sideshift.api.QueryOrderStatus;
|
||||
import com.m2049r.xmrwallet.service.shift.ShiftCallback;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
|
||||
import lombok.Getter;
|
||||
import timber.log.Timber;
|
||||
|
||||
class QueryOrderStatusImpl implements QueryOrderStatus {
|
||||
|
||||
@Getter
|
||||
private QueryOrderStatus.State state;
|
||||
@Getter
|
||||
private final String orderId;
|
||||
@Getter
|
||||
private final Date createdAt;
|
||||
@Getter
|
||||
private final Date expiresAt;
|
||||
@Getter
|
||||
private final double btcAmount;
|
||||
@Getter
|
||||
private final String btcAddress;
|
||||
@Getter
|
||||
private final double xmrAmount;
|
||||
@Getter
|
||||
private final String xmrAddress;
|
||||
|
||||
public boolean isCreated() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isTerminal() {
|
||||
return (state.equals(State.SETTLED) || isError());
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return state.equals(State.UNDEFINED);
|
||||
}
|
||||
|
||||
public boolean isWaiting() {
|
||||
return state.equals(State.WAITING);
|
||||
}
|
||||
|
||||
public boolean isPending() {
|
||||
return state.equals(State.PENDING);
|
||||
}
|
||||
|
||||
public boolean isSent() {
|
||||
return state.equals(State.SETTLING);
|
||||
}
|
||||
|
||||
public boolean isPaid() {
|
||||
return state.equals(State.SETTLED);
|
||||
}
|
||||
|
||||
public double getPrice() {
|
||||
return btcAmount / xmrAmount;
|
||||
}
|
||||
|
||||
QueryOrderStatusImpl(final JSONObject jsonObject) throws JSONException {
|
||||
try {
|
||||
String created = jsonObject.getString("createdAtISO");
|
||||
createdAt = DateHelper.parse(created);
|
||||
String expires = jsonObject.getString("expiresAtISO");
|
||||
expiresAt = DateHelper.parse(expires);
|
||||
} catch (ParseException ex) {
|
||||
throw new JSONException(ex.getLocalizedMessage());
|
||||
}
|
||||
orderId = jsonObject.getString("orderId");
|
||||
|
||||
btcAmount = jsonObject.getDouble("settleAmount");
|
||||
JSONObject settleAddress = jsonObject.getJSONObject("settleAddress");
|
||||
btcAddress = settleAddress.getString("address");
|
||||
|
||||
xmrAmount = jsonObject.getDouble("depositAmount");
|
||||
JSONObject depositAddress = jsonObject.getJSONObject("depositAddress");
|
||||
xmrAddress = settleAddress.getString("address");
|
||||
|
||||
JSONArray deposits = jsonObject.getJSONArray("deposits");
|
||||
// we only create one deposit, so die if there are more than one:
|
||||
if (deposits.length() > 1)
|
||||
throw new IllegalStateException("more than one deposits");
|
||||
|
||||
state = State.UNDEFINED;
|
||||
if (deposits.length() == 0) {
|
||||
state = State.WAITING;
|
||||
} else if (deposits.length() == 1) {
|
||||
// sanity check
|
||||
if (!orderId.equals(deposits.getJSONObject(0).getString("orderId")))
|
||||
throw new IllegalStateException("deposit has different order id!");
|
||||
String stateName = deposits.getJSONObject(0).getString("status");
|
||||
try {
|
||||
state = State.valueOf(stateName.toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
state = State.UNDEFINED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void call(@NonNull final ShiftApiCall api, @NonNull final String orderId,
|
||||
@NonNull final ShiftCallback<QueryOrderStatus> callback) {
|
||||
api.call("orders/" + orderId, new NetworkCallback() {
|
||||
@Override
|
||||
public void onSuccess(JSONObject jsonObject) {
|
||||
try {
|
||||
callback.onSuccess(new QueryOrderStatusImpl(jsonObject));
|
||||
} catch (JSONException ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.service.shift.sideshift.network;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.m2049r.xmrwallet.service.shift.NetworkCallback;
|
||||
import com.m2049r.xmrwallet.service.shift.ShiftApiCall;
|
||||
import com.m2049r.xmrwallet.util.DateHelper;
|
||||
import com.m2049r.xmrwallet.service.shift.sideshift.api.RequestQuote;
|
||||
import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
|
||||
import com.m2049r.xmrwallet.service.shift.ShiftCallback;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
|
||||
import lombok.Getter;
|
||||
import timber.log.Timber;
|
||||
|
||||
class RequestQuoteImpl implements RequestQuote {
|
||||
@Getter
|
||||
private final double btcAmount;
|
||||
@Getter
|
||||
private final String id;
|
||||
@Getter
|
||||
private final Date createdAt;
|
||||
@Getter
|
||||
private final Date expiresAt;
|
||||
@Getter
|
||||
private final double xmrAmount;
|
||||
@Getter
|
||||
private final double price;
|
||||
|
||||
// TODO do something with errors - they always seem to send us 500
|
||||
|
||||
RequestQuoteImpl(final JSONObject jsonObject) throws JSONException {
|
||||
// sanity checks
|
||||
final String depositMethod = jsonObject.getString("depositMethod");
|
||||
final String settleMethod = jsonObject.getString("settleMethod");
|
||||
if (!"xmr".equals(depositMethod) || !SideShiftApi.ASSET.equals(settleMethod))
|
||||
throw new IllegalStateException();
|
||||
|
||||
btcAmount = jsonObject.getDouble("settleAmount");
|
||||
id = jsonObject.getString("id");
|
||||
|
||||
try {
|
||||
final String created = jsonObject.getString("createdAt");
|
||||
createdAt = DateHelper.parse(created);
|
||||
final String expires = jsonObject.getString("expiresAt");
|
||||
expiresAt = DateHelper.parse(expires);
|
||||
} catch (ParseException ex) {
|
||||
throw new JSONException(ex.getLocalizedMessage());
|
||||
}
|
||||
xmrAmount = jsonObject.getDouble("depositAmount");
|
||||
price = jsonObject.getDouble("rate");
|
||||
}
|
||||
|
||||
public static void call(@NonNull final ShiftApiCall api, final double xmrAmount,
|
||||
@NonNull final ShiftCallback<RequestQuote> callback) {
|
||||
try {
|
||||
final JSONObject request = createRequest(xmrAmount);
|
||||
api.call("quotes", request, new NetworkCallback() {
|
||||
@Override
|
||||
public void onSuccess(JSONObject jsonObject) {
|
||||
try {
|
||||
callback.onSuccess(new RequestQuoteImpl(jsonObject));
|
||||
} catch (JSONException ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
});
|
||||
} catch (JSONException ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create JSON request object
|
||||
*
|
||||
* @param xmrAmount how much XMR to shift to BTC
|
||||
*/
|
||||
|
||||
static JSONObject createRequest(final double xmrAmount) throws JSONException {
|
||||
final JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("depositMethod", "xmr");
|
||||
jsonObject.put("settleMethod", SideShiftApi.ASSET);
|
||||
// #sideshift is silly and likes numbers as strings
|
||||
String amount = AmountFormatter.format(xmrAmount);
|
||||
jsonObject.put("depositAmount", amount);
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
static DecimalFormat AmountFormatter = new DecimalFormat("#.############");
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r er al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.util;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class DateHelper {
|
||||
public static final SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
||||
|
||||
public static Date parse(String dateString) throws ParseException {
|
||||
return DATETIME_FORMATTER.parse(dateString.replaceAll("Z$", "+0000"));
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Specs from https://openalias.org/
|
||||
|
||||
package com.m2049r.xmrwallet.util;
|
||||
|
||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||
import com.m2049r.xmrwallet.xmrto.api.CreateOrder;
|
||||
import com.m2049r.xmrwallet.xmrto.api.XmrToApi;
|
||||
import com.m2049r.xmrwallet.xmrto.api.XmrToCallback;
|
||||
import com.m2049r.xmrwallet.xmrto.network.XmrToApiImpl;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class PaymentProtocolHelper {
|
||||
|
||||
//https://bitpay.com/i/xxx
|
||||
public static boolean isHttp(String string) {
|
||||
if ((string == null) || (string.isEmpty())) return false;
|
||||
try {
|
||||
// new URL(string).toURI() checks if its a real url
|
||||
return new URL(string).toURI().getScheme().startsWith("http");
|
||||
} catch (MalformedURLException | URISyntaxException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// guess if the string may be a valid payment uri
|
||||
//https://bitpay.com/i/xxx
|
||||
//bitcoin:?r=https://bitpay.com/i/xxx
|
||||
public static String getBip70(String bip72Or70) {
|
||||
if ((bip72Or70 == null) || (bip72Or70.isEmpty())) return null;
|
||||
if (isHttp(bip72Or70)) return bip72Or70;
|
||||
BarcodeData bc = BarcodeData.parseBitcoinUri(bip72Or70);
|
||||
if (bc == null) return null;
|
||||
return bc.bip70;
|
||||
}
|
||||
|
||||
public interface OnResolvedListener {
|
||||
void onResolved(BarcodeData.Asset asset, String address, double amount, String bip70);
|
||||
|
||||
void onFailure(Exception ex);
|
||||
|
||||
}
|
||||
|
||||
static public boolean resolve(final String bip70, final OnResolvedListener resolvedListener) {
|
||||
if ((bip70 == null) || (bip70.isEmpty()))
|
||||
return false; //pointless trying to lookup nothing
|
||||
Timber.d("Resolving %s", bip70);
|
||||
getXmrToApi().createOrder(bip70, new XmrToCallback<CreateOrder>() {
|
||||
@Override
|
||||
public void onSuccess(CreateOrder createOrder) {
|
||||
if (resolvedListener != null) {
|
||||
resolvedListener.onResolved(BarcodeData.Asset.BTC,
|
||||
createOrder.getBtcDestAddress(),
|
||||
createOrder.getBtcAmount(),
|
||||
createOrder.getBtcBip70());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception ex) {
|
||||
if (resolvedListener != null) {
|
||||
resolvedListener.onFailure(ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
static private XmrToApi xmrToApi = null;
|
||||
|
||||
static private XmrToApi getXmrToApi() {
|
||||
if (xmrToApi == null) {
|
||||
synchronized (PaymentProtocolHelper.class) {
|
||||
if (xmrToApi == null) {
|
||||
xmrToApi = new XmrToApiImpl(OkHttpHelper.getOkHttpClient(),
|
||||
Helper.getXmrToBaseUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return xmrToApi;
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.xmrto;
|
||||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class XmrToError {
|
||||
private final Error errorId;
|
||||
private final String errorMsg;
|
||||
|
||||
public enum Error {
|
||||
XMRTO_ERROR_UNDEF,
|
||||
XMRTO_ERROR_001, // (503) internal services not available try again later
|
||||
XMRTO_ERROR_002, // (400) malformed bitcoin address check address validity
|
||||
XMRTO_ERROR_003, // (400) invalid bitcoin amount check amount data type
|
||||
XMRTO_ERROR_004, // (400) bitcoin amount out of bounds check min and max amount
|
||||
XMRTO_ERROR_005, // (400) unexpected validation error contact support
|
||||
XMRTO_ERROR_006, // (404) requested order not found check order UUID
|
||||
XMRTO_ERROR_007, // (503) third party service not available try again later
|
||||
XMRTO_ERROR_008, // (503) insufficient funds available try again later
|
||||
XMRTO_ERROR_009, // (400) invalid request check request parameters
|
||||
XMRTO_ERROR_010, // (400) payment protocol failed invalid or outdated data served by url
|
||||
XMRTO_ERROR_011, // (400) malformed payment protocol url url is malformed or cannot be contacted
|
||||
XMRTO_ERROR_012 // (403) too many requests
|
||||
}
|
||||
|
||||
public boolean isRetryable() {
|
||||
return (errorId == Error.XMRTO_ERROR_001)
|
||||
|| (errorId == Error.XMRTO_ERROR_007)
|
||||
|| (errorId == Error.XMRTO_ERROR_008);
|
||||
}
|
||||
|
||||
public static String getErrorIdString(Error anError) {
|
||||
return anError.toString().replace('_', '-');
|
||||
}
|
||||
|
||||
// mostly for testing
|
||||
public XmrToError(String errorId, String message) {
|
||||
Error error;
|
||||
try {
|
||||
error = Error.valueOf(errorId.replace('-', '_'));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
error = Error.XMRTO_ERROR_UNDEF;
|
||||
}
|
||||
this.errorId = error;
|
||||
this.errorMsg = message;
|
||||
}
|
||||
|
||||
public XmrToError(final JSONObject jsonObject) throws JSONException {
|
||||
final String errorId = jsonObject.getString("error");
|
||||
Error error;
|
||||
try {
|
||||
error = Error.valueOf(errorId.replace('-', '_'));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
error = Error.XMRTO_ERROR_UNDEF;
|
||||
}
|
||||
this.errorId = error;
|
||||
this.errorMsg = jsonObject.getString("error_msg");
|
||||
}
|
||||
|
||||
public Error getErrorId() {
|
||||
return errorId;
|
||||
}
|
||||
|
||||
public String getErrorMsg() {
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
public int getErrorMsgId() {
|
||||
switch (errorId) {
|
||||
case XMRTO_ERROR_001:
|
||||
return R.string.xmrto_error_001;
|
||||
case XMRTO_ERROR_004:
|
||||
return R.string.xmrto_error_004;
|
||||
case XMRTO_ERROR_010:
|
||||
return R.string.xmrto_error_010;
|
||||
case XMRTO_ERROR_012:
|
||||
return R.string.xmrto_error_012;
|
||||
default:
|
||||
return R.string.xmrto_error;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getErrorIdString(getErrorId()) + ": " + getErrorMsg();
|
||||
}
|
||||
|
||||
/* Errors from Query Parameters
|
||||
HTTP code XMR.TO error code Error message/reason Solution
|
||||
503 XMRTO-ERROR-001 internal services not available try again later
|
||||
503 XMRTO-ERROR-007 third party service not available try again later
|
||||
503 XMRTO-ERROR-008 insufficient funds available try again later
|
||||
*/
|
||||
|
||||
/* Errors from Create Order
|
||||
HTTP code XMR.TO error code Error message/reason Solution
|
||||
503 XMRTO-ERROR-001 internal services not available try again later
|
||||
400 XMRTO-ERROR-002 malformed bitcoin address check address validity
|
||||
400 XMRTO-ERROR-003 invalid bitcoin amount check amount data type
|
||||
503 XMRTO-ERROR-004 bitcoin amount out of bounds check min and max amount
|
||||
400 XMRTO-ERROR-005 unexpected validation error contact support
|
||||
|
||||
Errors from Create Order Payment Protocol
|
||||
400 XMRTO-ERROR-010 payment protocol failed invalid or outdated data served by url
|
||||
400 XMRTO-ERROR-011 malformed payment protocol url url is malformed or cannot be contacted
|
||||
*/
|
||||
|
||||
/* Errors from Query Order
|
||||
HTTP code XMR.TO error code Error message/reason Solution
|
||||
400 XMRTO-ERROR-009 invalid request check request parameters
|
||||
404 XMRTO-ERROR-006 requested order not found check order UUID
|
||||
*/
|
||||
|
||||
/* General
|
||||
403 XMRTO-ERROR-012 too many requests
|
||||
*/
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.xmrto;
|
||||
|
||||
public class XmrToException extends Exception {
|
||||
private int code;
|
||||
private XmrToError error;
|
||||
|
||||
public XmrToException(final int code) {
|
||||
super();
|
||||
this.code = code;
|
||||
this.error = null;
|
||||
}
|
||||
|
||||
public XmrToException(final int code, final XmrToError error) {
|
||||
super();
|
||||
this.code = code;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public XmrToError getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.xmrto.api;
|
||||
|
||||
public interface QueryOrderParameters {
|
||||
|
||||
double getLowerLimit(); // "lower_limit": <lower_order_limit_in_btc_as_float>,
|
||||
|
||||
double getPrice(); // "price": <price_of_1_btc_in_xmr_as_offered_by_service_as_float>,
|
||||
|
||||
double getUpperLimit(); // "upper_limit": <upper_order_limit_in_btc_as_float>,
|
||||
|
||||
boolean isZeroConfEnabled(); // "zero_conf_enabled": <true_if_zero_conf_is_enabled_as_boolean>,
|
||||
|
||||
double getZeroConfMaxAmount(); // "zero_conf_max_amount": <up_to_this_amount_zero_conf_is_possible_as_float>
|
||||
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.xmrto.api;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public interface XmrToApi {
|
||||
|
||||
/**
|
||||
* Queries the order parameter.
|
||||
*
|
||||
* @param callback the callback with the OrderParameter object
|
||||
*/
|
||||
void queryOrderParameters(@NonNull final XmrToCallback<QueryOrderParameters> callback);
|
||||
|
||||
/**
|
||||
* Creates an order
|
||||
*
|
||||
* @param amount the desired amount
|
||||
* @param address the target bitcoin address
|
||||
*/
|
||||
void createOrder(final double amount, @NonNull final String address, @NonNull final XmrToCallback<CreateOrder> callback);
|
||||
|
||||
/**
|
||||
* Creates an order through BIP70 payment protocol like bitpay
|
||||
*
|
||||
* @param url the BIP70 URL
|
||||
*/
|
||||
void createOrder(@NonNull final String url, @NonNull final XmrToCallback<CreateOrder> callback);
|
||||
|
||||
/**
|
||||
* Queries the order status for given current order
|
||||
*
|
||||
* @param uuid the order uuid
|
||||
* @param callback the callback with the OrderStatus object
|
||||
*/
|
||||
void queryOrderStatus(@NonNull final String uuid, @NonNull final XmrToCallback<QueryOrderStatus> callback);
|
||||
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.xmrto.network;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.m2049r.xmrwallet.xmrto.api.CreateOrder;
|
||||
import com.m2049r.xmrwallet.xmrto.api.XmrToCallback;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
class CreateOrderImpl implements CreateOrder {
|
||||
|
||||
private final String state;
|
||||
private final double btcAmount;
|
||||
private final String btcDestAddress;
|
||||
private final String btcBip70;
|
||||
private final String uuid;
|
||||
|
||||
public Double getBtcAmount() {
|
||||
return btcAmount;
|
||||
}
|
||||
|
||||
public String getBtcDestAddress() {
|
||||
return btcDestAddress;
|
||||
}
|
||||
|
||||
public String getBtcBip70() {
|
||||
return btcBip70;
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
CreateOrderImpl(final JSONObject jsonObject) throws JSONException {
|
||||
this.state = jsonObject.getString("state");
|
||||
this.btcAmount = jsonObject.getDouble("btc_amount");
|
||||
this.btcDestAddress = jsonObject.getString("btc_dest_address");
|
||||
if (jsonObject.has("pp_url"))
|
||||
this.btcBip70 = jsonObject.getString("pp_url");
|
||||
else
|
||||
this.btcBip70 = null;
|
||||
this.uuid = jsonObject.getString("uuid");
|
||||
}
|
||||
|
||||
public static void call(@NonNull final XmrToApiCall api, final double amount, @NonNull final String address,
|
||||
@NonNull final XmrToCallback<CreateOrder> callback) {
|
||||
try {
|
||||
final JSONObject request = createRequest(amount, address);
|
||||
api.call("order_create", request, new NetworkCallback() {
|
||||
@Override
|
||||
public void onSuccess(JSONObject jsonObject) {
|
||||
try {
|
||||
callback.onSuccess(new CreateOrderImpl(jsonObject));
|
||||
} catch (JSONException ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
});
|
||||
} catch (JSONException ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void call(@NonNull final XmrToApiCall api, @NonNull final String url,
|
||||
@NonNull final XmrToCallback<CreateOrder> callback) {
|
||||
try {
|
||||
final JSONObject request = createRequest(url);
|
||||
api.call("order_create_pp", request, new NetworkCallback() {
|
||||
@Override
|
||||
public void onSuccess(JSONObject jsonObject) {
|
||||
try {
|
||||
callback.onSuccess(new CreateOrderImpl(jsonObject));
|
||||
} catch (JSONException ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
});
|
||||
} catch (JSONException ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static JSONObject createRequest(final double amount, final String address) throws JSONException {
|
||||
final JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("amount", amount);
|
||||
jsonObject.put("amount_currency", "BTC");
|
||||
jsonObject.put("btc_dest_address", address);
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
static JSONObject createRequest(final String ppUrl) throws JSONException {
|
||||
final JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("pp_url", ppUrl);
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
}
|
@ -1,220 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.xmrto.network;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.m2049r.xmrwallet.xmrto.api.XmrToCallback;
|
||||
import com.m2049r.xmrwallet.xmrto.api.QueryOrderStatus;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
class QueryOrderStatusImpl implements QueryOrderStatus {
|
||||
public static final SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
|
||||
public static Date parseDate(String dateString) throws ParseException {
|
||||
return DATETIME_FORMATTER.parse(dateString.replaceAll("Z$", "+0000"));
|
||||
}
|
||||
|
||||
private QueryOrderStatus.State state; // "state": "<order_state_as_string>",
|
||||
private double btcAmount; // "btc_amount": <requested_amount_in_btc_as_float>,
|
||||
private String btcDestAddress; // "btc_dest_address": "<requested_destination_address_as_string>",
|
||||
private String uuid; // "uuid": "<unique_order_identifier_as_12_character_string>"
|
||||
// the following are only returned if the state is "after" TO_BE_CREATED
|
||||
//private int btcNumConfirmations; // "btc_num_confirmations": <btc_num_confirmations_as_integer>,
|
||||
private int btcNumConfirmationsThreshold; // "btc_num_confirmations_threshold": <btc_num_confirmations_threshold_as_integer>,
|
||||
private Date createdAt; // "created_at": "<timestamp_as_string>",
|
||||
private Date expiresAt; // "expires_at": "<timestamp_as_string>",
|
||||
private int secondsTillTimeout; // "seconds_till_timeout": <seconds_till_timeout_as_integer>,
|
||||
private double incomingAmountTotal; // "incoming_amount_total": <amount_in_incoming_currency_for_this_order_as_float>,
|
||||
private double remainingAmountIncoming; // "remaining_amount_incoming": <amount_in_incoming_currency_that_the_user_must_still_send_as_float>,
|
||||
private int incomingNumConfirmationsRemaining; // "incoming_num_confirmations_remaining": <num_incoming_currency_confirmations_remaining_before_bitcoins_will_be_sent_as_integer>,
|
||||
private double incomingPriceBtc; // "incoming_price_btc": <price_of_1_incoming_in_btc_currency_as_offered_by_service_as_float>,
|
||||
private String receivingSubaddress; // "receiving_subaddress": <xmr_subaddress_user_needs_to_send_funds_to_as_string>,
|
||||
private int recommendedMixin; // "recommended_mixin": <recommended_mixin_as_integer>,
|
||||
|
||||
public QueryOrderStatus.State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public double getBtcAmount() {
|
||||
return btcAmount;
|
||||
}
|
||||
|
||||
public String getBtcDestAddress() {
|
||||
return btcDestAddress;
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public int getBtcNumConfirmationsThreshold() {
|
||||
return btcNumConfirmationsThreshold;
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public Date getExpiresAt() {
|
||||
return expiresAt;
|
||||
}
|
||||
|
||||
public int getSecondsTillTimeout() {
|
||||
return secondsTillTimeout;
|
||||
}
|
||||
|
||||
public double getIncomingAmountTotal() {
|
||||
return incomingAmountTotal;
|
||||
}
|
||||
|
||||
public double getRemainingAmountIncoming() {
|
||||
return remainingAmountIncoming;
|
||||
}
|
||||
|
||||
public int getIncomingNumConfirmationsRemaining() {
|
||||
return incomingNumConfirmationsRemaining;
|
||||
}
|
||||
|
||||
public double getIncomingPriceBtc() {
|
||||
return incomingPriceBtc;
|
||||
}
|
||||
|
||||
public String getReceivingSubaddress() {
|
||||
return receivingSubaddress;
|
||||
}
|
||||
|
||||
public int getRecommendedMixin() {
|
||||
return recommendedMixin;
|
||||
}
|
||||
|
||||
public boolean isCreated() {
|
||||
return (state.equals(State.UNPAID) ||
|
||||
state.equals(State.BTC_SENT) ||
|
||||
state.equals(State.PAID) ||
|
||||
state.equals(State.PAID_UNCONFIRMED) ||
|
||||
state.equals(State.UNDERPAID));
|
||||
}
|
||||
|
||||
public boolean isTerminal() {
|
||||
return (state.equals(State.BTC_SENT) || isError());
|
||||
}
|
||||
|
||||
|
||||
public boolean isError() {
|
||||
return (state.equals(State.UNDEF) ||
|
||||
state.equals(State.NOT_FOUND) ||
|
||||
state.equals(State.TIMED_OUT));
|
||||
}
|
||||
|
||||
public boolean isPending() {
|
||||
return (state.equals(State.TO_BE_CREATED) ||
|
||||
state.equals(State.UNPAID) ||
|
||||
state.equals(State.UNDERPAID) ||
|
||||
state.equals(State.PAID_UNCONFIRMED) ||
|
||||
state.equals(State.PAID));
|
||||
}
|
||||
|
||||
public boolean isPaid() {
|
||||
return (state.equals(State.PAID_UNCONFIRMED) ||
|
||||
state.equals(State.PAID));
|
||||
}
|
||||
|
||||
public boolean isSent() {
|
||||
return state.equals(State.BTC_SENT);
|
||||
}
|
||||
|
||||
|
||||
QueryOrderStatusImpl(final JSONObject jsonObject) throws JSONException {
|
||||
Timber.d(jsonObject.toString(4));
|
||||
String stateName = jsonObject.getString("state"); // "state": "<order_state_as_string>",
|
||||
State state;
|
||||
try {
|
||||
state = State.valueOf(stateName);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
state = State.UNDEF; //TODO: throws IllegalArgumentException?
|
||||
}
|
||||
this.state = state;
|
||||
|
||||
btcAmount = jsonObject.getDouble("btc_amount"); // "btc_amount": <requested_amount_in_btc_as_float>,
|
||||
btcDestAddress = jsonObject.getString("btc_dest_address"); // "btc_dest_address": "<requested_destination_address_as_string>",
|
||||
uuid = jsonObject.getString("uuid"); // "uuid": "<unique_order_identifier_as_12_character_string>"
|
||||
|
||||
if (isCreated()) {
|
||||
btcNumConfirmationsThreshold = jsonObject.getInt("btc_num_confirmations_threshold");
|
||||
try {
|
||||
String created = jsonObject.getString("created_at");
|
||||
createdAt = parseDate(created);
|
||||
String expires = jsonObject.getString("expires_at");
|
||||
expiresAt = parseDate(expires);
|
||||
} catch (ParseException ex) {
|
||||
throw new JSONException(ex.getLocalizedMessage());
|
||||
}
|
||||
secondsTillTimeout = jsonObject.getInt("seconds_till_timeout");
|
||||
incomingAmountTotal = jsonObject.getDouble("incoming_amount_total");
|
||||
remainingAmountIncoming = jsonObject.getDouble("remaining_amount_incoming");
|
||||
incomingNumConfirmationsRemaining = jsonObject.getInt("incoming_num_confirmations_remaining");
|
||||
incomingPriceBtc = jsonObject.getDouble("incoming_price_btc");
|
||||
receivingSubaddress = jsonObject.getString("receiving_subaddress");
|
||||
recommendedMixin = jsonObject.getInt("recommended_mixin");
|
||||
}
|
||||
}
|
||||
|
||||
public static void call(@NonNull final XmrToApiCall api, @NonNull final String uuid,
|
||||
@NonNull final XmrToCallback<QueryOrderStatus> callback) {
|
||||
try {
|
||||
final JSONObject request = createRequest(uuid);
|
||||
api.call("order_status_query", request, new NetworkCallback() {
|
||||
@Override
|
||||
public void onSuccess(JSONObject jsonObject) {
|
||||
try {
|
||||
callback.onSuccess(new QueryOrderStatusImpl(jsonObject));
|
||||
} catch (JSONException ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
});
|
||||
} catch (JSONException ex) {
|
||||
callback.onError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create JSON request object
|
||||
*
|
||||
* @param uuid unique_order_identifier_as_12_character_string
|
||||
*/
|
||||
|
||||
static JSONObject createRequest(final String uuid) throws JSONException {
|
||||
final JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("uuid", uuid);
|
||||
return jsonObject;
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19,19H5V5h7V3H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2v7zM14,3v2h3.59l-9.83,9.83 1.41,1.41L19,6.41V10h2V3h-7z"/>
|
||||
</vector>
|
@ -0,0 +1,48 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="648dp"
|
||||
android:height="80dp"
|
||||
android:viewportWidth="648"
|
||||
android:viewportHeight="80">
|
||||
<path
|
||||
android:pathData="M65.94,9.56A40,40 0,0 0,9.56 66Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
<path
|
||||
android:pathData="M13.79,70.23a40,40 0,0 0,56.45 -56.5Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
<path
|
||||
android:pathData="M144.75,28a9.12,9.12 0,0 0,-1 -4.48A8.81,8.81 0,0 0,141 20.29a14.14,14.14 0,0 0,-4 -1.95,15.61 15.61,0 0,0 -4.84,-0.68 15.34,15.34 0,0 0,-4.24 0.58,11.88 11.88,0 0,0 -3.55,1.66 7.15,7.15 0,0 0,-2.47 2.63,7.26 7.26,0 0,0 -0.88,3.61v0.49a7.11,7.11 0,0 0,0.88 3.7A6.91,6.91 0,0 0,124.53 33,19 19,0 0,0 129,34.82a58.17,58.17 0,0 0,6.31 1.27C140.9,37 145,38.52 147.61,41a12.31,12.31 0,0 1,3.94 9.66v0.87a16,16 0,0 1,-1.18 6.25,13.23 13.23,0 0,1 -3.55,4.87 17,17 0,0 1,-5.72 3.22,24.6 24.6,0 0,1 -8,1.17A26.21,26.21 0,0 1,124 65.54a18,18 0,0 1,-6.6 -4.1,18.51 18.51,0 0,1 -4.05,-6.14A21.41,21.41 0,0 1,112 47.59V45.35h6.41V47.2c0,4.68 1.28,8.1 3.85,10.44s6.11,3.51 10.75,3.51c4,0 7,-0.88 9,-2.63a8.82,8.82 0,0 0,3 -6.93V51.1a7.26,7.26 0,0 0,-3 -6.33q-3.12,-2.21 -10.06,-3.22a38.07,38.07 0,0 1,-7.3 -1.66,17.24 17.24,0 0,1 -5.53,-2.83 13.62,13.62 0,0 1,-3.55 -4.29,13.48 13.48,0 0,1 -1.18,-5.85V26a11.87,11.87 0,0 1,1.28 -5.65,13.37 13.37,0 0,1 3.65,-4.49A16.94,16.94 0,0 1,124.92 13a26.31,26.31 0,0 1,15.19 0.29,21.17 21.17,0 0,1 6,3.41 14.69,14.69 0,0 1,5 11.12V31h-6.41V28Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
<path
|
||||
android:pathData="M161.91,12.68h33.93v5.85H182.13V59.59h13.71v5.85H161.91V59.59h13.71v-41H161.91Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
<path
|
||||
android:pathData="M207.78,12.68h17.56q9.91,0 14.5,4.68c3,3.12 4.53,8.1 4.53,14.92L244.37,45.84c0,6.82 -1.48,11.8 -4.53,14.92s-7.89,4.68 -14.5,4.68L207.78,65.44L207.78,59.49h4.54L212.32,18.63h-4.54ZM224.45,59.68a22.74,22.74 0,0 0,6.11 -0.69,9.73 9.73,0 0,0 4.24,-2.34 9.43,9.43 0,0 0,2.47 -4.39,26.62 26.62,0 0,0 0.79,-6.82L238.06,32.77a26.2,26.2 0,0 0,-0.79 -6.83,10 10,0 0,0 -2.47,-4.38 9.73,9.73 0,0 0,-4.24 -2.34,22.26 22.26,0 0,0 -6.11,-0.69h-5.62L218.83,59.59h5.62Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
<path
|
||||
android:pathData="M256.21,12.68h32.35v5.85H262.62V36.09h25.55v5.85H262.62V59.59h26.43v5.85H256.21Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
<path
|
||||
android:pathData="M331.67,28a9.12,9.12 0,0 0,-1 -4.48,8.81 8.81,0 0,0 -2.76,-3.22 14.2,14.2 0,0 0,-4.05 -1.95,15.55 15.55,0 0,0 -4.83,-0.68 15.34,15.34 0,0 0,-4.24 0.58,11.77 11.77,0 0,0 -3.55,1.66 7.07,7.07 0,0 0,-2.47 2.63,7.26 7.26,0 0,0 -0.89,3.61v0.49a7.11,7.11 0,0 0,0.89 3.7A6.91,6.91 0,0 0,311.45 33a19,19 0,0 0,4.44 1.85,58.17 58.17,0 0,0 6.31,1.27c5.62,0.87 9.76,2.43 12.33,4.87a12.31,12.31 0,0 1,3.94 9.66v0.87a16,16 0,0 1,-1.18 6.25,13.23 13.23,0 0,1 -3.55,4.87A17,17 0,0 1,328 65.83,24.64 24.64,0 0,1 320,67 26.21,26.21 0,0 1,311 65.54a18.09,18.09 0,0 1,-6.61 -4.1,18.63 18.63,0 0,1 -4,-6.14 21.41,21.41 0,0 1,-1.38 -7.71V45.35h6.41V47.2c0,4.68 1.28,8.1 3.85,10.44s6.11,3.51 10.75,3.51c3.94,0 7,-0.88 9,-2.63A8.8,8.8 0,0 0,332 51.59V51.1a7.24,7.24 0,0 0,-3.06 -6.33q-3.11,-2.21 -10.06,-3.22a38,38 0,0 1,-7.29 -1.66A17.24,17.24 0,0 1,306 37.06a13.62,13.62 0,0 1,-3.55 -4.29,13.48 13.48,0 0,1 -1.18,-5.85V26a11.87,11.87 0,0 1,1.28 -5.65,13.37 13.37,0 0,1 3.65,-4.49A16.94,16.94 0,0 1,311.84 13a26.31,26.31 0,0 1,15.19 0.29,21.17 21.17,0 0,1 6,3.41 14.69,14.69 0,0 1,5 11.12V31h-6.41Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
<path
|
||||
android:pathData="M348,12.68h6.41V36.09h22.79V12.68h6.41V65.54h-6.41V42H354.45V65.63H348Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
<path
|
||||
android:pathData="M395.68,12.68h33.93v5.85H415.9V59.59h13.71v5.85H395.68V59.59h13.71v-41H395.68Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
<path
|
||||
android:pathData="M443.23,12.68h32.84v5.85H449.64V36.09h25.94v5.85H449.64v23.6h-6.41V12.68Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
<path
|
||||
android:pathData="M487.32,12.68H524.9v5.85H509.32v47H502.9V18.63H487.32V12.68Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
<path
|
||||
android:pathData="M537.33,61.34a4.74,4.74 0,0 1,1.58 -3.7,5 5,0 0,1 3.74,-1.56A5.36,5.36 0,0 1,548 61.34a4.76,4.76 0,0 1,-1.58 3.71,5 5,0 0,1 -3.75,1.56 4.86,4.86 0,0 1,-3.74 -1.56A4.76,4.76 0,0 1,537.33 61.34Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
<path
|
||||
android:pathData="M595.82,52.47H572.94l-3.85,13.16h-6.91l16.08,-52.95h12l16.17,52.86h-6.9ZM583.89,15.41l-9.28,31.11H594l-9.27,-31.11Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
<path
|
||||
android:pathData="M614.07,12.68H648v5.85H634.29V59.59H648v5.85H614.07V59.59h13.71v-41H614.07Z"
|
||||
android:fillColor="@color/monerujoPrimary"/>
|
||||
</vector>
|
@ -0,0 +1,51 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="404.08dp"
|
||||
android:height="115dp"
|
||||
android:viewportWidth="404.08"
|
||||
android:viewportHeight="115">
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M62.65,0c1.62,0.49 3.29,0.92 4.9,1.48q40,13.85 48,55.41c0.55,2.9 0.69,5.89 1,9 -0.77,0 -1.24,0.09 -1.72,0.09L63.76,65.98c-0.93,0 -1.73,0.13 -1.72,-1.32q0.06,-32.19 0,-64.39L62.04,0ZM84.65,56.41A14.19,14.19 0,1 0,70.54 42.26,14.24 14.24,0 0,0 84.69,56.42Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M0,64.28c0.45,-2.48 0.76,-5 1.36,-7.43A46.65,46.65 0,0 1,18.08 30.92c0.38,-0.3 0.8,-0.57 1.06,-0.75L54.82,65.85a8.61,8.61 0,0 1,-1 0.12H1c-0.32,0 -0.64,0 -0.95,-0.06Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M404.08,80c-0.3,1.32 -0.54,2.65 -0.92,3.94a18.5,18.5 0,0 1,-17.33 13.41c-5.26,0.28 -10.16,-0.78 -14.34,-4.19 -6.61,-5.39 -8.86,-15.45 -5.33,-23.85A17.89,17.89 0,0 1,377.91 58.7c9.55,-2.91 19.6,0.92 23.81,9.27 1.15,2.29 1.59,5 2.36,7.43ZM384.25,66.48a9.62,9.62 0,0 0,-9.1 5.91,13 13,0 0,0 -0.84,7.83 9.85,9.85 0,0 0,9.53 8.44c5.18,0.14 9.08,-2.76 10.2,-7.87a15.52,15.52 0,0 0,0.19 -5.35A10.18,10.18 0,0 0,384.25 66.48Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M0,70l21.15,0H41.61L12.15,99.4c-0.63,-0.73 -1.44,-1.63 -2.17,-2.56A46.27,46.27 0,0 1,0.24 72.38a7.28,7.28 0,0 0,-0.24 -1Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M46.1,115c-1.2,-0.1 -2.41,-0.23 -3.61,-0.32 -0.76,-0.06 -1.29,-0.25 -1.28,-1.19 0,-6.9 0,-13.81 0,-20.71a0.89,0.89 0,0 1,0.08 -0.32L60.55,111.7a14.44,14.44 0,0 1,-2.31 0.94c-3.1,0.76 -6.22,1.43 -9.33,2.13l-1.18,0.23Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M205,60.58V71.13c0,8 0,15.91 0,23.87 0,1.2 -0.29,1.66 -1.58,1.63q-4.87,-0.13 -9.76,0c-1.3,0 -1.69,-0.35 -1.69,-1.67 0.06,-8.85 0,-17.71 0,-26.57V42.08c0,-0.58 0,-1.16 0.08,-1.81a5.77,5.77 0,0 1,0.83 -0.15c4,0 8,0 12.07,0a2.61,2.61 0,0 1,1.66 1.09c4.79,6.5 9.53,13.06 14.29,19.6 0.29,0.39 0.6,0.78 1,1.28l2,-2.7q6.63,-9.09 13.22,-18.2a2.4,2.4 0,0 1,2.24 -1.14c3.61,0.06 7.23,0 10.84,0 1.07,0 1.51,0.21 1.51,1.4q0,26.85 0,53.69c0,1.16 -0.39,1.45 -1.48,1.43 -3.3,-0.06 -6.6,-0.08 -9.9,0 -1.27,0 -1.59,-0.39 -1.58,-1.61 0,-10.89 0,-21.78 0,-32.67V60.9l-0.27,-0.09c-0.32,0.41 -0.64,0.81 -0.95,1.23l-13,17.36c-1.7,2.27 -4.08,2.22 -5.78,-0.1L205.93,61.67C205.72,61.4 205.49,61.14 205,60.58Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M315.57,96.55h-1.32c-4.43,0 -8.86,0 -13.29,0a2.84,2.84 0,0 1,-2.44 -1.08c-4.51,-5.24 -9.09,-10.42 -13.59,-15.67a3.11,3.11 0,0 0,-2.79 -1.24,46.84 46.84,0 0,1 -4.74,0c-1,0 -1.32,0.31 -1.31,1.32 0,5 0,10 0,15 0,1.2 -0.27,1.66 -1.57,1.63 -3.34,-0.09 -6.68,-0.06 -10,0 -1,0 -1.45,-0.25 -1.45,-1.36q0,-27 0,-53.95c0,-1 0.32,-1.35 1.33,-1.35 9.35,0.08 18.71,0 28,0.25A18.39,18.39 0,0 1,310.34 55c1.46,7.37 0.05,14.08 -6.22,19a40.92,40.92 0,0 1,-5.46 3.12l17.06,19.11ZM276.11,66.42a3,3 0,0 0,0.65 0.19c4.79,0 9.59,0.17 14.37,-0.06A6.75,6.75 0,0 0,298 59.18c-0.18,-4.09 -3.06,-6.83 -7.37,-6.87s-8.76,0 -13.15,0c-1.11,0 -1.37,0.42 -1.35,1.44 0.06,2.12 0,4.24 0,6.37Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M157.7,77.48l-7,10.36c-1.78,2.61 -3.53,5.25 -5.36,7.83a2.1,2.1 0,0 1,-1.36 0.85c-4.43,0.06 -8.86,0 -13.29,0a3,3 0,0 1,-0.57 -0.15c0.27,-0.46 0.5,-0.87 0.77,-1.26 5.95,-8.63 11.88,-17.27 17.87,-25.86a1.9,1.9 0,0 0,0 -2.6q-8.7,-12.53 -17.32,-25.1c-0.27,-0.39 -0.52,-0.81 -0.9,-1.39 0.61,0 1,-0.12 1.36,-0.12 4,0 8,0 11.93,0a2.22,2.22 0,0 1,2.08 1.14q5.46,8.25 11,16.45c0.24,0.36 0.51,0.72 0.86,1.21 1.17,-1.72 2.26,-3.31 3.34,-4.92 2.85,-4.23 5.69,-8.46 8.51,-12.73A2.18,2.18 0,0 1,171.65 40c4,0.05 8,0 12.07,0 0.4,0 0.81,0 1.48,0.08 -0.36,0.59 -0.61,1 -0.9,1.44q-8.79,12.54 -17.61,25.07a1.86,1.86 0,0 0,0 2.59q9.17,12.95 18.23,26c0.26,0.36 0.49,0.74 0.82,1.26 -0.47,0 -0.75,0.1 -1,0.1 -4.2,0 -8.41,0 -12.61,0a2.31,2.31 0,0 1,-2.18 -1.21q-5.61,-8.31 -11.28,-16.59C158.38,78.41 158.11,78.06 157.7,77.48Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M23,27.23c2.89,-1.24 6,-2.79 9.25,-3.9A45.78,45.78 0,0 1,56.86 22c0.9,0.19 1.26,0.55 1.25,1.53q0,19.17 0,38.35a2,2 0,0 1,0 0.43Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M349.05,47.9v8.92c0,1.82 0,1.83 1.88,1.83 2.39,0 4.78,0 7.18,0 1,0 1.49,0.28 1.45,1.38 -0.07,1.85 -0.05,3.7 0,5.55 0,0.94 -0.34,1.27 -1.27,1.25 -2.72,0 -5.43,0 -8.14,0 -0.88,0 -1.2,0.31 -1.19,1.19 0,5.15 0,10.3 0.07,15.46 0.08,3.77 2.56,5.61 6.28,4.84 1,-0.21 2,-0.54 3.11,-0.87L361,95.32A19.21,19.21 0,0 1,351 97c-7.19,-0.66 -11.34,-5.28 -11.48,-12.76 -0.1,-5.29 -0.08,-10.58 0,-15.86 0,-1.29 -0.42,-1.62 -1.63,-1.56 -1.44,0.09 -2.88,0 -4.34,0 -0.78,0 -1.15,-0.23 -1.13,-1.09q0.06,-3 0,-6c0,-0.82 0.29,-1.14 1.1,-1.12 1.58,0 3.16,0 4.74,0 1,0 1.26,-0.34 1.24,-1.27 -0.06,-2.44 0,-4.88 0,-7.32 0,-0.42 0.39,-1.15 0.67,-1.18C343.06,48.51 345.93,48.23 349.05,47.9Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M60,91.89c1.61,-3.39 2.71,-6.55 -0.15,-9.51a4.78,4.78 0,0 0,-5.8 -0.95,6.59 6.59,0 0,1 0.86,0.27c3.52,1.87 3.21,6.48 0.24,8.7 -4.61,3.44 -12.18,0.51 -13.64,-5.32a12.17,12.17 0,0 1,10 -14.78c9.8,-1.74 21.6,3.82 23.87,16.11a28.87,28.87 0,0 1,0.4 4.45c0,0.34 -0.54,1 -0.84,1C70.08,91.91 65.17,91.89 60,91.89Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M15.46,102.57 L37,81v32.54C32.57,113.87 19.14,107 15.46,102.57Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M51.48,96.07h24c-1.07,2.1 -1.9,4 -3,5.79a23.32,23.32 0,0 1,-7.18 7.08,1.32 1.32,0 0,1 -1.24,0c-4.15,-4.07 -8.25,-8.22 -12.36,-12.34C51.61,96.52 51.59,96.37 51.48,96.07Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M322.92,91.56a5.19,5.19 0,0 1,5.6 -5.42,5.52 5.52,0 1,1 -0.17,11A5.24,5.24 0,0 1,322.92 91.56Z"/>
|
||||
<path
|
||||
android:fillColor="@color/monerujoPrimary"
|
||||
android:pathData="M84.91,31.38A10.91,10.91 0,1 1,73.79 42.27,10.9 10.9,0 0,1 84.91,31.38ZM86.45,36.3a3.57,3.57 0,0 0,-3.63 3.51v0.06a3.76,3.76 0,0 0,3.62 3.67,3.65 3.65,0 0,0 3.65,-3.66v-0.06A3.48,3.48 0,0 0,86.45 36.3Z"/>
|
||||
</vector>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue