mirror of
https://github.com/haveno-dex/haveno.git
synced 2026-01-09 19:41:01 -05:00
Merge 8abd17804c into 3400665e94
This commit is contained in:
commit
8dce2e1ea4
7 changed files with 433 additions and 8 deletions
164
core/src/main/java/haveno/core/util/MoneroUriUtils.java
Normal file
164
core/src/main/java/haveno/core/util/MoneroUriUtils.java
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Haveno.
|
||||
*
|
||||
* Haveno is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Haveno is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package haveno.core.util;
|
||||
|
||||
import monero.wallet.model.MoneroDestination;
|
||||
import monero.wallet.model.MoneroTxConfig;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class MoneroUriUtils {
|
||||
|
||||
public static String makeUri(List<MoneroDestination> destinations, String label) {
|
||||
if (destinations == null || destinations.isEmpty()) {
|
||||
throw new IllegalArgumentException("Destinations cannot be null or empty");
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder("monero:");
|
||||
|
||||
// Append addresses separated by semicolon
|
||||
for (int i = 0; i < destinations.size(); i++) {
|
||||
sb.append(destinations.get(i).getAddress());
|
||||
if (i < destinations.size() - 1) {
|
||||
sb.append(";");
|
||||
}
|
||||
}
|
||||
|
||||
boolean firstParam = true;
|
||||
|
||||
// Check if any amount is present
|
||||
boolean hasAmounts = false;
|
||||
for (MoneroDestination dest : destinations) {
|
||||
if (dest.getAmount() != null) {
|
||||
hasAmounts = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasAmounts) {
|
||||
sb.append("?tx_amount=");
|
||||
for (int i = 0; i < destinations.size(); i++) {
|
||||
BigInteger amount = destinations.get(i).getAmount();
|
||||
if (amount != null) {
|
||||
String amountStr = new BigDecimal(amount).divide(new BigDecimal("1000000000000")).stripTrailingZeros().toPlainString();
|
||||
if (!amountStr.contains(".")) amountStr += ".0";
|
||||
sb.append(amountStr);
|
||||
}
|
||||
if (i < destinations.size() - 1) {
|
||||
sb.append(";");
|
||||
}
|
||||
}
|
||||
firstParam = false;
|
||||
}
|
||||
|
||||
if (label != null && !label.isEmpty()) {
|
||||
sb.append(firstParam ? "?" : "&");
|
||||
sb.append("tx_description=").append(URLEncoder.encode(label, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static MoneroTxConfig parseUri(String uriStr) {
|
||||
if (uriStr == null || !uriStr.startsWith("monero:")) {
|
||||
throw new IllegalArgumentException("Invalid Monero URI");
|
||||
}
|
||||
|
||||
String content = uriStr.substring("monero:".length());
|
||||
String path;
|
||||
String query = null;
|
||||
|
||||
int queryIndex = content.indexOf('?');
|
||||
if (queryIndex != -1) {
|
||||
path = content.substring(0, queryIndex);
|
||||
query = content.substring(queryIndex + 1);
|
||||
} else {
|
||||
path = content;
|
||||
}
|
||||
|
||||
String[] addresses = path.split(";");
|
||||
Map<String, String> params = parseQuery(query);
|
||||
|
||||
List<MoneroDestination> destinations = new ArrayList<>();
|
||||
String[] amounts = params.getOrDefault("tx_amount", "").split(";");
|
||||
|
||||
for (int i = 0; i < addresses.length; i++) {
|
||||
BigInteger atomicAmount = null;
|
||||
if (i < amounts.length && !amounts[i].isEmpty()) {
|
||||
try {
|
||||
atomicAmount = new BigDecimal(amounts[i]).multiply(new BigDecimal("1000000000000")).toBigInteger();
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
destinations.add(new MoneroDestination(addresses[i], atomicAmount));
|
||||
}
|
||||
|
||||
MoneroTxConfig config = new MoneroTxConfig().setDestinations(destinations);
|
||||
|
||||
// Extract note from potential label/description parameters
|
||||
String note = params.get("tx_description");
|
||||
if (note == null || note.isEmpty()) note = params.get("tx_note");
|
||||
if (note == null || note.isEmpty()) note = params.get("recipient_name");
|
||||
if (note == null || note.isEmpty()) note = params.get("label");
|
||||
|
||||
if (note != null && !note.isEmpty()) {
|
||||
config.setNote(note);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
private static Map<String, String> parseQuery(String query) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
if (query == null || query.isEmpty()) return params;
|
||||
|
||||
String[] pairs = query.split("&");
|
||||
for (String pair : pairs) {
|
||||
int idx = pair.indexOf("=");
|
||||
if (idx != -1) {
|
||||
String key = URLDecoder.decode(pair.substring(0, idx), StandardCharsets.UTF_8);
|
||||
String value = URLDecoder.decode(pair.substring(idx + 1), StandardCharsets.UTF_8);
|
||||
params.put(key, value);
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
}
|
||||
104
core/src/test/java/haveno/core/util/BountyVerification.java
Normal file
104
core/src/test/java/haveno/core/util/BountyVerification.java
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Haveno.
|
||||
*
|
||||
* Haveno is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Haveno is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package haveno.core.util;
|
||||
|
||||
import monero.wallet.model.MoneroDestination;
|
||||
import monero.wallet.model.MoneroTxConfig;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class BountyVerification {
|
||||
|
||||
@Test
|
||||
public void verifyBountyImplementation() {
|
||||
System.out.println("=== Monero Multi-Destination URI Bounty Verification ===\n");
|
||||
|
||||
// 1. Setup multiple destinations with special characters and different amounts
|
||||
List<MoneroDestination> originalDestinations = new ArrayList<>();
|
||||
originalDestinations.add(new MoneroDestination("44AFFq5kSiGBo3SnoCmcQC9R9X1844vAbaE74EutH43AnuW98jod9iTAwAsWAByY2v7r6Y1844vAbaE74EutH43AnuW98jod", new BigInteger("1234567890123"))); // 1.234567890123 XMR (High precision)
|
||||
originalDestinations.add(new MoneroDestination("888tNkS9pU7649sbs19JpS7eJEXfK7X9VvCjS8q63nU2y26H07f6n3vCjS8q63nU2y26H07f6n3vCjS8q63nU2y26H07", new BigInteger("750000000000"))); // 0.75 XMR
|
||||
String label = "Haveno Donation & Support; [Test]"; // Testing encoding and semicolons
|
||||
|
||||
System.out.println("Original Destinations:");
|
||||
for (MoneroDestination dest : originalDestinations) {
|
||||
System.out.println(" - Address: " + dest.getAddress());
|
||||
System.out.println(" Amount: " + dest.getAmount() + " atomic units");
|
||||
}
|
||||
System.out.println("Label: " + label + "\n");
|
||||
|
||||
// 2. Generate URI
|
||||
String generatedUri = MoneroUriUtils.makeUri(originalDestinations, label);
|
||||
System.out.println("Generated URI (Standard Compliant):");
|
||||
System.out.println(generatedUri + "\n");
|
||||
|
||||
// 3. Parse URI
|
||||
System.out.println("Parsing generated URI...");
|
||||
MoneroTxConfig parsedConfig = MoneroUriUtils.parseUri(generatedUri);
|
||||
List<MoneroDestination> parsedDestinations = parsedConfig.getDestinations();
|
||||
|
||||
System.out.println("\nParsed Results:");
|
||||
boolean allMatch = true;
|
||||
if (parsedDestinations.size() != originalDestinations.size()) {
|
||||
System.err.println("Error: Destination count mismatch!");
|
||||
allMatch = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < parsedDestinations.size(); i++) {
|
||||
MoneroDestination orig = originalDestinations.get(i);
|
||||
MoneroDestination parsed = parsedDestinations.get(i);
|
||||
|
||||
System.out.println("Destination #" + (i + 1) + ":");
|
||||
System.out.println(" Address Match: " + parsed.getAddress().equals(orig.getAddress()));
|
||||
System.out.println(" Amount Match: " + parsed.getAmount().equals(orig.getAmount()) + " (" + parsed.getAmount() + ")");
|
||||
|
||||
if (!parsed.getAddress().equals(orig.getAddress()) || !parsed.getAmount().equals(orig.getAmount())) {
|
||||
allMatch = false;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Label Match: " + parsedConfig.getNote().equals(label));
|
||||
if (!parsedConfig.getNote().equals(label)) allMatch = false;
|
||||
|
||||
if (allMatch) {
|
||||
System.out.println("\nVERIFICATION SUCCESSFUL: Implementation is correct and standard-compliant.");
|
||||
} else {
|
||||
System.err.println("\nVERIFICATION FAILED: Mismatch detected.");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
84
core/src/test/java/haveno/core/util/MoneroUriUtilsTest.java
Normal file
84
core/src/test/java/haveno/core/util/MoneroUriUtilsTest.java
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Haveno.
|
||||
*
|
||||
* Haveno is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Haveno is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package haveno.core.util;
|
||||
|
||||
import monero.wallet.model.MoneroDestination;
|
||||
import monero.wallet.model.MoneroTxConfig;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
public class MoneroUriUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testMakeUriSingle() {
|
||||
List<MoneroDestination> destinations = List.of(new MoneroDestination("addr1", new BigInteger("1000000000000")));
|
||||
String uri = MoneroUriUtils.makeUri(destinations, "test");
|
||||
assertEquals("monero:addr1?tx_amount=1.0&tx_description=test", uri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeUriMultiple() {
|
||||
List<MoneroDestination> destinations = new ArrayList<>();
|
||||
destinations.add(new MoneroDestination("addr1", new BigInteger("1000000000000")));
|
||||
destinations.add(new MoneroDestination("addr2", new BigInteger("500000000000")));
|
||||
String uri = MoneroUriUtils.makeUri(destinations, "donations");
|
||||
assertEquals("monero:addr1;addr2?tx_amount=1.0;0.5&tx_description=donations", uri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseUriMultiple() {
|
||||
String uri = "monero:addr1;addr2?tx_amount=1.0;0.5&tx_description=donations";
|
||||
MoneroTxConfig config = MoneroUriUtils.parseUri(uri);
|
||||
assertEquals(2, config.getDestinations().size());
|
||||
assertEquals("addr1", config.getDestinations().get(0).getAddress());
|
||||
assertEquals(new BigInteger("1000000000000"), config.getDestinations().get(0).getAmount());
|
||||
assertEquals("addr2", config.getDestinations().get(1).getAddress());
|
||||
assertEquals(new BigInteger("500000000000"), config.getDestinations().get(1).getAmount());
|
||||
assertEquals("donations", config.getNote());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseUriWithNoAmounts() {
|
||||
String uri = "monero:addr1;addr2?tx_description=test";
|
||||
MoneroTxConfig config = MoneroUriUtils.parseUri(uri);
|
||||
assertEquals(2, config.getDestinations().size());
|
||||
assertNull(config.getDestinations().get(0).getAmount());
|
||||
assertNull(config.getDestinations().get(1).getAmount());
|
||||
}
|
||||
}
|
||||
|
|
@ -73,7 +73,12 @@ import haveno.proto.grpc.UnlockWalletReply;
|
|||
import haveno.proto.grpc.UnlockWalletRequest;
|
||||
import haveno.proto.grpc.GetWalletHeightRequest;
|
||||
import haveno.proto.grpc.GetWalletHeightReply;
|
||||
import haveno.proto.grpc.MakeMoneroUriReply;
|
||||
import haveno.proto.grpc.MakeMoneroUriRequest;
|
||||
import haveno.proto.grpc.ParseMoneroUriReply;
|
||||
import haveno.proto.grpc.ParseMoneroUriRequest;
|
||||
import haveno.proto.grpc.WalletsGrpc.WalletsImplBase;
|
||||
import haveno.core.util.MoneroUriUtils;
|
||||
import static haveno.proto.grpc.WalletsGrpc.getGetAddressBalanceMethod;
|
||||
import static haveno.proto.grpc.WalletsGrpc.getGetBalancesMethod;
|
||||
import static haveno.proto.grpc.WalletsGrpc.getGetFundingAddressesMethod;
|
||||
|
|
@ -334,6 +339,41 @@ class GrpcWalletsService extends WalletsImplBase {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void makeMoneroUri(MakeMoneroUriRequest req, StreamObserver<MakeMoneroUriReply> responseObserver) {
|
||||
try {
|
||||
List<MoneroDestination> destinations = req.getDestinationsList().stream()
|
||||
.map(d -> new MoneroDestination(d.getAddress(), d.getAmount().isEmpty() ? null : new BigInteger(d.getAmount())))
|
||||
.collect(Collectors.toList());
|
||||
String uri = MoneroUriUtils.makeUri(destinations, req.getLabel());
|
||||
var reply = MakeMoneroUriReply.newBuilder().setUri(uri).build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
} catch (Throwable cause) {
|
||||
exceptionHandler.handleException(log, cause, responseObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseMoneroUri(ParseMoneroUriRequest req, StreamObserver<ParseMoneroUriReply> responseObserver) {
|
||||
try {
|
||||
var txConfig = MoneroUriUtils.parseUri(req.getUri());
|
||||
var reply = ParseMoneroUriReply.newBuilder()
|
||||
.addAllDestinations(txConfig.getDestinations().stream()
|
||||
.map(d -> haveno.proto.grpc.XmrDestination.newBuilder()
|
||||
.setAddress(d.getAddress())
|
||||
.setAmount(d.getAmount() == null ? "" : d.getAmount().toString())
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
.setLabel(txConfig.getNote() == null ? "" : txConfig.getNote())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
} catch (Throwable cause) {
|
||||
exceptionHandler.handleException(log, cause, responseObserver);
|
||||
}
|
||||
}
|
||||
|
||||
final ServerInterceptor[] interceptors() {
|
||||
Optional<ServerInterceptor> rateMeteringInterceptor = rateMeteringInterceptor();
|
||||
return rateMeteringInterceptor.map(serverInterceptor ->
|
||||
|
|
|
|||
|
|
@ -116,8 +116,15 @@ public class AssetsForm extends PaymentMethodForm {
|
|||
addressInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
|
||||
if (newValue.startsWith("monero:")) {
|
||||
UserThread.execute(() -> {
|
||||
String addressWithoutPrefix = newValue.replace("monero:", "");
|
||||
addressInputTextField.setText(addressWithoutPrefix);
|
||||
try {
|
||||
monero.wallet.model.MoneroTxConfig config = haveno.core.util.MoneroUriUtils.parseUri(newValue);
|
||||
if (!config.getDestinations().isEmpty()) {
|
||||
addressInputTextField.setText(config.getDestinations().get(0).getAddress());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String addressWithoutPrefix = newValue.replace("monero:", "");
|
||||
addressInputTextField.setText(addressWithoutPrefix);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,8 +55,10 @@ import haveno.core.user.DontShowAgainLookup;
|
|||
import haveno.core.user.Preferences;
|
||||
import haveno.core.user.User;
|
||||
import haveno.core.util.FormattingUtils;
|
||||
import haveno.core.util.MoneroUriUtils;
|
||||
import haveno.core.util.coin.CoinFormatter;
|
||||
import haveno.core.xmr.wallet.XmrWalletService;
|
||||
import monero.wallet.model.MoneroDestination;
|
||||
import haveno.desktop.Navigation;
|
||||
import haveno.desktop.components.AutoTooltipLabel;
|
||||
import haveno.desktop.components.HavenoTextArea;
|
||||
|
|
@ -110,9 +112,7 @@ import javafx.stage.StageStyle;
|
|||
import javafx.util.Callback;
|
||||
import javafx.util.StringConverter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import monero.common.MoneroUtils;
|
||||
import monero.daemon.model.MoneroTx;
|
||||
import monero.wallet.model.MoneroTxConfig;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
|
@ -765,10 +765,14 @@ public class GUIUtil {
|
|||
}
|
||||
|
||||
public static String getMoneroURI(String address, BigInteger amount, String label) {
|
||||
MoneroTxConfig txConfig = new MoneroTxConfig().setAddress(address);
|
||||
if (amount != null) txConfig.setAmount(amount);
|
||||
if (label != null && !label.isEmpty() && !disablePaymentUriLabel) txConfig.setNote(label);
|
||||
return MoneroUtils.getPaymentUri(txConfig);
|
||||
List<MoneroDestination> destinations = List.of(new MoneroDestination(address, amount));
|
||||
String finalLabel = (label != null && !label.isEmpty() && !disablePaymentUriLabel) ? label : null;
|
||||
return MoneroUriUtils.makeUri(destinations, finalLabel);
|
||||
}
|
||||
|
||||
public static String getMoneroURI(List<MoneroDestination> destinations, String label) {
|
||||
String finalLabel = (label != null && !label.isEmpty() && !disablePaymentUriLabel) ? label : null;
|
||||
return MoneroUriUtils.makeUri(destinations, finalLabel);
|
||||
}
|
||||
|
||||
public static boolean isBootstrappedOrShowPopup(P2PService p2PService) {
|
||||
|
|
|
|||
|
|
@ -1002,6 +1002,10 @@ service Wallets {
|
|||
}
|
||||
rpc GetHeight (GetWalletHeightRequest) returns (GetWalletHeightReply) {
|
||||
}
|
||||
rpc MakeMoneroUri (MakeMoneroUriRequest) returns (MakeMoneroUriReply) {
|
||||
}
|
||||
rpc ParseMoneroUri (ParseMoneroUriRequest) returns (ParseMoneroUriReply) {
|
||||
}
|
||||
}
|
||||
|
||||
message GetBalancesRequest {
|
||||
|
|
@ -1184,3 +1188,21 @@ message GetWalletHeightReply {
|
|||
int64 height = 1;
|
||||
int64 target_height = 2;
|
||||
}
|
||||
|
||||
message MakeMoneroUriRequest {
|
||||
repeated XmrDestination destinations = 1;
|
||||
string label = 2;
|
||||
}
|
||||
|
||||
message MakeMoneroUriReply {
|
||||
string uri = 1;
|
||||
}
|
||||
|
||||
message ParseMoneroUriRequest {
|
||||
string uri = 1;
|
||||
}
|
||||
|
||||
message ParseMoneroUriReply {
|
||||
repeated XmrDestination destinations = 1;
|
||||
string label = 2;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue