From 5bf7bba0c661ffecadc71962c2b13a12ec56f40a Mon Sep 17 00:00:00 2001 From: jmacxx <47253594+jmacxx@users.noreply.github.com> Date: Wed, 10 Nov 2021 14:23:04 -0600 Subject: [PATCH] Changes required for GRIN re-listing --- .../java/bisq/asset/GrinAddressValidator.java | 102 ------------------ .../src/main/java/bisq/asset/coins/Grin.java | 29 ++++- .../test/java/bisq/asset/coins/GrinTest.java | 26 +++-- .../resources/i18n/displayStrings.properties | 10 +- 4 files changed, 50 insertions(+), 117 deletions(-) delete mode 100644 assets/src/main/java/bisq/asset/GrinAddressValidator.java diff --git a/assets/src/main/java/bisq/asset/GrinAddressValidator.java b/assets/src/main/java/bisq/asset/GrinAddressValidator.java deleted file mode 100644 index f397bca0bae..00000000000 --- a/assets/src/main/java/bisq/asset/GrinAddressValidator.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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 . - */ - -package bisq.asset; - -/** - * We only support the grinbox format as it is currently the only tool which offers a validation options of sender. - * Beside that is the IP:port format very insecure with MITM attacks. - * - * Here is the information from a conversation with the Grinbox developer regarding the Grinbox address format. - * - A Grinbox address is of the format: grinbox://@domain.com:port where everything besides is optional. - If no domain is specified, the default relay grinbox.io will be used. - - The is a base58check encoded value (like in Bitcoin). For Grin mainnet, the first 2 bytes will be [1, 11] and - the following 33 bytes should be a valid secp256k1 compressed public key. - - Some examples of valid addresses are: - - gVvRNiuopubvxPrs1BzJdQjVdFAxmkLzMqiVJzUZ7ubznhdtNTGB - gVvUcSafSTD3YTSqgNf9ojEYWkz3zMZNfsjdpdb9en5mxc6gmja6 - gVvk7rLBg3r3qoWYL3VsREnBbooT7nynxx5HtDvUWCJUaNCnddvY - grinbox://gVtWzX5NTLCBkyNV19QVdnLXue13heAVRD36sfkGD6xpqy7k7e4a - gVw9TWimGFXRjoDXWhWxeNQbu84ZpLkvnenkKvA5aJeDo31eM5tC@somerelay.com - grinbox://gVwjSsYW5vvHpK4AunJ5piKhhQTV6V3Jb818Uqs6PdC3SsB36AsA@somerelay.com:1220 - - Some examples of invalid addresses are: - - gVuBJDKcWkhueMfBLAbFwV4ax55YXPeinWXdRME1Zi3eiC6sFNye (invalid checksum) - geWGCMQjxZMHG3EtTaRbR7rH9rE4DsmLfpm1iiZEa7HFKjjkgpf2 (wrong version bytes) - gVvddC2jYAfxTxnikcbTEQKLjhJZpqpBg39tXkwAKnD2Pys2mWiK (invalid public key) - - We only add the basic validation without checksum, version byte and pubkey validation as that would require much more - effort. Any Grin developer is welcome to add that though! - - */ -public class GrinAddressValidator implements AddressValidator { - // A Grin Wallet URL (address is not the correct term) can be in the form IP:port or a grinbox format. - // The grinbox has the format grinbox://@domain.com:port where everything beside the key is optional. - - - // Regex for IP validation borrowed from https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses - private static final String PORT = "((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4}))$"; - private static final String DOMAIN = "[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\\.[a-zA-Z]{2,}$"; - private static final String KEY = "[a-km-zA-HJ-NP-Z1-9]{52}$"; - - public GrinAddressValidator() { - } - - @Override - public AddressValidationResult validate(String address) { - if (address == null || address.length() == 0) - return AddressValidationResult.invalidAddress("Address may not be empty (only Grinbox format is supported)"); - - // We only support grinbox address - String key; - String domain = null; - String port = null; - address = address.replace("grinbox://", ""); - if (address.contains("@")) { - String[] keyAndDomain = address.split("@"); - key = keyAndDomain[0]; - if (keyAndDomain.length > 1) { - domain = keyAndDomain[1]; - if (domain.contains(":")) { - String[] domainAndPort = domain.split(":"); - domain = domainAndPort[0]; - if (domainAndPort.length > 1) - port = domainAndPort[1]; - } - } - } else { - key = address; - } - - if (!key.matches("^" + KEY)) - return AddressValidationResult.invalidAddress("Invalid key (only Grinbox format is supported)"); - - if (domain != null && !domain.matches("^" + DOMAIN)) - return AddressValidationResult.invalidAddress("Invalid domain (only Grinbox format is supported)"); - - if (port != null && !port.matches("^" + PORT)) - return AddressValidationResult.invalidAddress("Invalid port (only Grinbox format is supported)"); - - return AddressValidationResult.validAddress(); - - } -} diff --git a/assets/src/main/java/bisq/asset/coins/Grin.java b/assets/src/main/java/bisq/asset/coins/Grin.java index 7812aacc294..b73c863284b 100644 --- a/assets/src/main/java/bisq/asset/coins/Grin.java +++ b/assets/src/main/java/bisq/asset/coins/Grin.java @@ -17,14 +17,39 @@ package bisq.asset.coins; +import bisq.asset.AddressValidationResult; +import bisq.asset.AddressValidator; import bisq.asset.AltCoinAccountDisclaimer; import bisq.asset.Coin; -import bisq.asset.GrinAddressValidator; + +import org.bitcoinj.core.AddressFormatException; +import org.bitcoinj.core.Bech32; @AltCoinAccountDisclaimer("account.altcoin.popup.grin.msg") public class Grin extends Coin { + static String coinName = "Grin"; + public Grin() { - super("Grin", "GRIN", new GrinAddressValidator()); + super(coinName, coinName.toUpperCase(), new GrinAddressValidator()); + } + + public static class GrinAddressValidator implements AddressValidator { + + @Override + public AddressValidationResult validate(String address) { + try { + Bech32.Bech32Data bechData = Bech32.decode(address); + if (!bechData.hrp.equals(coinName.toLowerCase())) { + return AddressValidationResult.invalidAddress(String.format("invalid address prefix %x", bechData.hrp)); + } + if (bechData.data.length != 52) { + return AddressValidationResult.invalidAddress(String.format("invalid address length %x", bechData.data.length)); + } + return AddressValidationResult.validAddress(); + } catch (AddressFormatException e) { + return AddressValidationResult.invalidStructure(); + } + } } } diff --git a/assets/src/test/java/bisq/asset/coins/GrinTest.java b/assets/src/test/java/bisq/asset/coins/GrinTest.java index 83b602607a8..bea8d71cae8 100644 --- a/assets/src/test/java/bisq/asset/coins/GrinTest.java +++ b/assets/src/test/java/bisq/asset/coins/GrinTest.java @@ -29,17 +29,29 @@ public GrinTest() { @Test public void testValidAddresses() { - // grinbox - assertValidAddress("gVvk7rLBg3r3qoWYL3VsREnBbooT7nynxx5HtDvUWCJUaNCnddvY"); - assertValidAddress("grinbox://gVtWzX5NTLCBkyNV19QVdnLXue13heAVRD36sfkGD6xpqy7k7e4a"); - assertValidAddress("gVw9TWimGFXRjoDXWhWxeNQbu84ZpLkvnenkKvA5aJeDo31eM5tC@somerelay.com"); - assertValidAddress("gVw9TWimGFXRjoDXWhWxeNQbu84ZpLkvnenkKvA5aJeDo31eM5tC@somerelay.com:1220"); - assertValidAddress("grinbox://gVwjSsYW5vvHpK4AunJ5piKhhQTV6V3Jb818Uqs6PdC3SsB36AsA@somerelay.com"); - assertValidAddress("grinbox://gVwjSsYW5vvHpK4AunJ5piKhhQTV6V3Jb818Uqs6PdC3SsB36AsA@somerelay.com:1220"); + // valid slatepack addresses + assertValidAddress("grin1ephxt0u33rz9zpl7exer2awfr9s9ae28qsx7908q2zq03uv3sj7suqdule"); + assertValidAddress("grin1wwg5k80qje0lw32ldttgl52lew0ucmv64zux27pzanl0a2ku85ps5gxafa"); + assertValidAddress("grin1mdxxaz8g5zc4fhqcvcu79c0sp3md9j2f6tt5cxde78scjatkh3zqzrgl9r"); + assertValidAddress("grin17whxsfzj3su0rtpd3hkcjt3hlatvc89dpc9syvrmq2shhnhc9f6sehqe3x"); + assertValidAddress("grin1cq636ment795xn68knzu0ewp73f3zdlgv6dsqv8x7vf2v0j4ek5sk6nmk3"); + assertValidAddress("grin1wm78wjsf2ws507hea4zqrcywxltjwhtgfrwzhdrr9l80l7tpz5fsj58lk0"); + assertValidAddress("grin1jezf3lkcexvj3ydjwanan6khs42fr4036guh0c4vkc04fyxarl6svjzuuh"); } @Test public void testInvalidAddresses() { + // invalid slatepack address (bech32 format invalid) + assertInvalidAddress("grin1p4fuklglxqsgg602hu4c4jl4aunu5tynyf4lkg96ezh3jefzpy6swshp5x"); // from 0015-slatepack.md#slatepackaddress + + // grinbox + assertInvalidAddress("gVvk7rLBg3r3qoWYL3VsREnBbooT7nynxx5HtDvUWCJUaNCnddvY"); + assertInvalidAddress("grinbox://gVtWzX5NTLCBkyNV19QVdnLXue13heAVRD36sfkGD6xpqy7k7e4a"); + assertInvalidAddress("gVw9TWimGFXRjoDXWhWxeNQbu84ZpLkvnenkKvA5aJeDo31eM5tC@somerelay.com"); + assertInvalidAddress("gVw9TWimGFXRjoDXWhWxeNQbu84ZpLkvnenkKvA5aJeDo31eM5tC@somerelay.com:1220"); + assertInvalidAddress("grinbox://gVwjSsYW5vvHpK4AunJ5piKhhQTV6V3Jb818Uqs6PdC3SsB36AsA@somerelay.com"); + assertInvalidAddress("grinbox://gVwjSsYW5vvHpK4AunJ5piKhhQTV6V3Jb818Uqs6PdC3SsB36AsA@somerelay.com:1220"); + // valid IP:port addresses but not supported in Bisq assertInvalidAddress("0.0.0.0:8080"); assertInvalidAddress("173.194.34.134:8080"); diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index c0102446e7b..c3eead303db 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -1729,15 +1729,13 @@ account.altcoin.popup.XZC.msg=When using Zcoin you can only use the transparent the untraceable addresses, because the mediator or arbitrator would not be able to verify the transaction with untraceable addresses at a block explorer. # suppress inspection "UnusedProperty" account.altcoin.popup.grin.msg=GRIN requires an interactive process between the sender and receiver to create the \ - transaction. Be sure to follow the instructions from the GRIN project web page to reliably send and receive GRIN \ - (the receiver needs to be online or at least be online during a certain time frame). \n\n\ - Bisq supports only the Grinbox (Wallet713) wallet URL format. \n\n\ + transaction. Be sure to follow the instructions from the GRIN project web page [HYPERLINK:https://grin.mw] to reliably send and receive GRIN. \ + More information on transacting GRIN can be found here [HYPERLINK:https://docs.grin.mw/about-grin/transactions/].\n\n\ The GRIN sender is required to provide proof that they have sent GRIN successfully. If the wallet cannot provide that proof, a \ potential dispute will be resolved in favor of the GRIN receiver. Please be sure that you use the \ - latest Grinbox software which supports the transaction proof and that you understand the process of transferring and \ + latest GRIN software which supports the transaction proof and that you understand the process of transferring and \ receiving GRIN as well as how to create the proof. \n\n\ - See https://github.com/vault713/wallet713/blob/master/docs/usage.md#transaction-proofs-grinbox-only for more \ - information about the Grinbox proof tool. + See [HYPERLINK:https://bisq.wiki/Trading_GRIN] for more information about trading GRIN on Bisq. # suppress inspection "UnusedProperty" account.altcoin.popup.beam.msg=BEAM requires an interactive process between the sender and receiver to create the \ transaction. \n\n\