Changes required for GRIN re-listing

This commit is contained in:
jmacxx 2021-11-10 14:23:04 -06:00
parent 284eaf2c11
commit 5bf7bba0c6
No known key found for this signature in database
GPG Key ID: 155297BABFE94A1B
4 changed files with 50 additions and 117 deletions

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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://<key>@domain.com:port where everything besides <key> is optional.
If no domain is specified, the default relay grinbox.io will be used.
The <key> 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://<key>@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();
}
}

View File

@ -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();
}
}
}
}

View File

@ -29,17 +29,29 @@ public class GrinTest extends AbstractAssetTest {
@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");

View File

@ -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\