From 7298a6373a1b4801da06bcff03f9c587164ef19e Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Sun, 10 Aug 2025 12:38:19 -0400 Subject: [PATCH] support Ripple (XRP) --- .../haveno/asset/RippleAddressValidator.java | 32 +++++++++++++ .../main/java/haveno/asset/coins/Ripple.java | 28 +++++++++++ .../META-INF/services/haveno.asset.Asset | 1 + .../java/haveno/asset/coins/RippleTest.java | 44 ++++++++++++++++++ .../java/haveno/core/locale/CurrencyUtil.java | 1 + .../src/main/java/haveno/desktop/images.css | 4 ++ .../src/main/resources/images/xrp_logo.png | Bin 0 -> 5397 bytes 7 files changed, 110 insertions(+) create mode 100644 assets/src/main/java/haveno/asset/RippleAddressValidator.java create mode 100644 assets/src/main/java/haveno/asset/coins/Ripple.java create mode 100644 assets/src/test/java/haveno/asset/coins/RippleTest.java create mode 100644 desktop/src/main/resources/images/xrp_logo.png diff --git a/assets/src/main/java/haveno/asset/RippleAddressValidator.java b/assets/src/main/java/haveno/asset/RippleAddressValidator.java new file mode 100644 index 0000000000..7325818143 --- /dev/null +++ b/assets/src/main/java/haveno/asset/RippleAddressValidator.java @@ -0,0 +1,32 @@ +/* + * 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 . + */ + +package haveno.asset; + +/** + * Validates a Ripple address using a regular expression. + */ +public class RippleAddressValidator extends RegexAddressValidator { + + public RippleAddressValidator() { + super("^r[1-9A-HJ-NP-Za-km-z]{25,34}$"); + } + + public RippleAddressValidator(String errorMessageI18nKey) { + super("^r[1-9A-HJ-NP-Za-km-z]{25,34}$", errorMessageI18nKey); + } +} diff --git a/assets/src/main/java/haveno/asset/coins/Ripple.java b/assets/src/main/java/haveno/asset/coins/Ripple.java new file mode 100644 index 0000000000..04ce84475d --- /dev/null +++ b/assets/src/main/java/haveno/asset/coins/Ripple.java @@ -0,0 +1,28 @@ +/* + * 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 . + */ + +package haveno.asset.coins; + +import haveno.asset.Coin; +import haveno.asset.RippleAddressValidator; + +public class Ripple extends Coin { + + public Ripple() { + super("Ripple", "XRP", new RippleAddressValidator()); + } +} diff --git a/assets/src/main/resources/META-INF/services/haveno.asset.Asset b/assets/src/main/resources/META-INF/services/haveno.asset.Asset index 80b9cd036d..a10943e769 100644 --- a/assets/src/main/resources/META-INF/services/haveno.asset.Asset +++ b/assets/src/main/resources/META-INF/services/haveno.asset.Asset @@ -7,6 +7,7 @@ haveno.asset.coins.BitcoinCash haveno.asset.coins.Ether haveno.asset.coins.Litecoin haveno.asset.coins.Monero +haveno.asset.coins.Ripple haveno.asset.tokens.TetherUSDERC20 haveno.asset.tokens.TetherUSDTRC20 haveno.asset.tokens.USDCoinERC20 diff --git a/assets/src/test/java/haveno/asset/coins/RippleTest.java b/assets/src/test/java/haveno/asset/coins/RippleTest.java new file mode 100644 index 0000000000..d984d78174 --- /dev/null +++ b/assets/src/test/java/haveno/asset/coins/RippleTest.java @@ -0,0 +1,44 @@ +/* + * 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 . + */ + +package haveno.asset.coins; + +import haveno.asset.AbstractAssetTest; +import org.junit.jupiter.api.Test; + +public class RippleTest extends AbstractAssetTest { + + public RippleTest() { + super(new Ripple()); + } + + @Test + public void testValidAddresses() { + assertValidAddress("r9CxAMAoZAgyVGP8CY9F1arzf9bJg3Y7U8"); + assertValidAddress("rsXMbDtCAmzSWajWiii7ffWygAjYVNDxY7"); + assertValidAddress("rE3nYkQy121JEVb37JKX8LSH6wUBnNvNo2"); + assertValidAddress("rMzucuWFUEE6aM9DC992BqqMgZNPrv4kvi"); + assertValidAddress("rJUmAFPWE36cpdbN4DUEAFBLtG2xkEavY8"); + } + + @Test + public void testInvalidAddresses() { + assertInvalidAddress("RJUmAFPWE36cpdbN4DUEAFBLtG2xkEavY8"); + assertInvalidAddress("zJUmAFPWE36cpdbN4DUEAFBLtG2xkEavY8"); + assertInvalidAddress("1LgfapHEPhZbRF9pMd5WPT35hFXcZS1USrW"); + } +} diff --git a/core/src/main/java/haveno/core/locale/CurrencyUtil.java b/core/src/main/java/haveno/core/locale/CurrencyUtil.java index 25605ab18a..e3b61eefaf 100644 --- a/core/src/main/java/haveno/core/locale/CurrencyUtil.java +++ b/core/src/main/java/haveno/core/locale/CurrencyUtil.java @@ -200,6 +200,7 @@ public class CurrencyUtil { result.add(new CryptoCurrency("BCH", "Bitcoin Cash")); result.add(new CryptoCurrency("ETH", "Ether")); result.add(new CryptoCurrency("LTC", "Litecoin")); + result.add(new CryptoCurrency("XRP", "Ripple")); result.add(new CryptoCurrency("DAI-ERC20", "Dai Stablecoin")); result.add(new CryptoCurrency("USDT-ERC20", "Tether USD")); result.add(new CryptoCurrency("USDT-TRC20", "Tether USD")); diff --git a/desktop/src/main/java/haveno/desktop/images.css b/desktop/src/main/java/haveno/desktop/images.css index c721f2ee7b..549549605e 100644 --- a/desktop/src/main/java/haveno/desktop/images.css +++ b/desktop/src/main/java/haveno/desktop/images.css @@ -353,6 +353,10 @@ -fx-image: url("../../images/xmr_logo.png"); } +#image-xrp-logo { + -fx-image: url("../../images/xrp_logo.png"); +} + #image-dark-mode-toggle { -fx-image: url("../../images/dark_mode_toggle.png"); } diff --git a/desktop/src/main/resources/images/xrp_logo.png b/desktop/src/main/resources/images/xrp_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0c1034a6c626764f2eef9499b6b01839c4e6079c GIT binary patch literal 5397 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 literal 0 HcmV?d00001