diff --git a/assets/svg/fruitSorbet/bitcoin.svg b/assets/images/dark/bitcoin.svg similarity index 100% rename from assets/svg/fruitSorbet/bitcoin.svg rename to assets/images/dark/bitcoin.svg diff --git a/assets/svg/fruitSorbet/bitcoincash.svg b/assets/images/dark/bitcoincash.svg similarity index 100% rename from assets/svg/fruitSorbet/bitcoincash.svg rename to assets/images/dark/bitcoincash.svg diff --git a/assets/svg/fruitSorbet/doge.svg b/assets/images/dark/doge.svg similarity index 100% rename from assets/svg/fruitSorbet/doge.svg rename to assets/images/dark/doge.svg diff --git a/assets/svg/fruitSorbet/firo.svg b/assets/images/dark/firo.svg similarity index 100% rename from assets/svg/fruitSorbet/firo.svg rename to assets/images/dark/firo.svg diff --git a/assets/images/dark/litecoin.svg b/assets/images/dark/litecoin.svg new file mode 100644 index 000000000..f224c429f --- /dev/null +++ b/assets/images/dark/litecoin.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/svg/fruitSorbet/particl.svg b/assets/images/dark/particl.svg similarity index 100% rename from assets/svg/fruitSorbet/particl.svg rename to assets/images/dark/particl.svg diff --git a/assets/images/dark/stack.svg b/assets/images/dark/stack.svg new file mode 100644 index 000000000..43f29e515 --- /dev/null +++ b/assets/images/dark/stack.svg @@ -0,0 +1,440 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/svg/fruitSorbet/wownero.svg b/assets/images/dark/wownero.svg similarity index 100% rename from assets/svg/fruitSorbet/wownero.svg rename to assets/images/dark/wownero.svg diff --git a/assets/images/forest/bitcoin.svg b/assets/images/forest/bitcoin.svg new file mode 100644 index 000000000..11b4e0b1e --- /dev/null +++ b/assets/images/forest/bitcoin.svg @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/forest/bitcoincash.svg b/assets/images/forest/bitcoincash.svg new file mode 100644 index 000000000..fec0dcfe1 --- /dev/null +++ b/assets/images/forest/bitcoincash.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/forest/doge.svg b/assets/images/forest/doge.svg new file mode 100644 index 000000000..2c1d693b4 --- /dev/null +++ b/assets/images/forest/doge.svg @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/forest/epic.png b/assets/images/forest/epic.png deleted file mode 100644 index 75b75c267..000000000 Binary files a/assets/images/forest/epic.png and /dev/null differ diff --git a/assets/images/forest/firo.svg b/assets/images/forest/firo.svg new file mode 100644 index 000000000..d1bddcd74 --- /dev/null +++ b/assets/images/forest/firo.svg @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/forest/litecoin.svg b/assets/images/forest/litecoin.svg new file mode 100644 index 000000000..f224c429f --- /dev/null +++ b/assets/images/forest/litecoin.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/forest/particl.svg b/assets/images/forest/particl.svg new file mode 100644 index 000000000..0084fa615 --- /dev/null +++ b/assets/images/forest/particl.svg @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/forest/stack.svg b/assets/images/forest/stack.svg new file mode 100644 index 000000000..cbb754036 --- /dev/null +++ b/assets/images/forest/stack.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/forest/wownero.svg b/assets/images/forest/wownero.svg new file mode 100644 index 000000000..7bcf97568 --- /dev/null +++ b/assets/images/forest/wownero.svg @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/fruitSorbet/bitcoin.svg b/assets/images/fruitSorbet/bitcoin.svg new file mode 100644 index 000000000..d3abd0954 --- /dev/null +++ b/assets/images/fruitSorbet/bitcoin.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/fruitSorbet/bitcoincash.svg b/assets/images/fruitSorbet/bitcoincash.svg new file mode 100644 index 000000000..6a10cce09 --- /dev/null +++ b/assets/images/fruitSorbet/bitcoincash.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/fruitSorbet/doge.svg b/assets/images/fruitSorbet/doge.svg new file mode 100644 index 000000000..2c1d693b4 --- /dev/null +++ b/assets/images/fruitSorbet/doge.svg @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/fruitSorbet/firo.svg b/assets/images/fruitSorbet/firo.svg new file mode 100644 index 000000000..6f502205c --- /dev/null +++ b/assets/images/fruitSorbet/firo.svg @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/fruitSorbet/litecoin.svg b/assets/images/fruitSorbet/litecoin.svg new file mode 100644 index 000000000..f224c429f --- /dev/null +++ b/assets/images/fruitSorbet/litecoin.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/fruitSorbet/particl.svg b/assets/images/fruitSorbet/particl.svg new file mode 100644 index 000000000..d15918985 --- /dev/null +++ b/assets/images/fruitSorbet/particl.svg @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/fruitSorbet/stack.svg b/assets/images/fruitSorbet/stack.svg new file mode 100644 index 000000000..cedb7e1d5 --- /dev/null +++ b/assets/images/fruitSorbet/stack.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/fruitSorbet/wownero.svg b/assets/images/fruitSorbet/wownero.svg new file mode 100644 index 000000000..812123542 --- /dev/null +++ b/assets/images/fruitSorbet/wownero.svg @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/light/bitcoin.svg b/assets/images/light/bitcoin.svg new file mode 100644 index 000000000..d3abd0954 --- /dev/null +++ b/assets/images/light/bitcoin.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/light/bitcoincash.svg b/assets/images/light/bitcoincash.svg new file mode 100644 index 000000000..6a10cce09 --- /dev/null +++ b/assets/images/light/bitcoincash.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/light/doge.svg b/assets/images/light/doge.svg new file mode 100644 index 000000000..2c1d693b4 --- /dev/null +++ b/assets/images/light/doge.svg @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/light/firo.svg b/assets/images/light/firo.svg new file mode 100644 index 000000000..6f502205c --- /dev/null +++ b/assets/images/light/firo.svg @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/light/litecoin.svg b/assets/images/light/litecoin.svg new file mode 100644 index 000000000..f224c429f --- /dev/null +++ b/assets/images/light/litecoin.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/light/particl.svg b/assets/images/light/particl.svg new file mode 100644 index 000000000..d15918985 --- /dev/null +++ b/assets/images/light/particl.svg @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/light/stack.svg b/assets/images/light/stack.svg new file mode 100644 index 000000000..43f29e515 --- /dev/null +++ b/assets/images/light/stack.svg @@ -0,0 +1,440 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/light/wownero.svg b/assets/images/light/wownero.svg new file mode 100644 index 000000000..812123542 --- /dev/null +++ b/assets/images/light/wownero.svg @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oceanBreeze/bitcoin.svg b/assets/images/oceanBreeze/bitcoin.svg new file mode 100644 index 000000000..d3abd0954 --- /dev/null +++ b/assets/images/oceanBreeze/bitcoin.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oceanBreeze/bitcoincash.svg b/assets/images/oceanBreeze/bitcoincash.svg new file mode 100644 index 000000000..6a10cce09 --- /dev/null +++ b/assets/images/oceanBreeze/bitcoincash.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oceanBreeze/doge.svg b/assets/images/oceanBreeze/doge.svg new file mode 100644 index 000000000..2c1d693b4 --- /dev/null +++ b/assets/images/oceanBreeze/doge.svg @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oceanBreeze/firo.svg b/assets/images/oceanBreeze/firo.svg new file mode 100644 index 000000000..6f502205c --- /dev/null +++ b/assets/images/oceanBreeze/firo.svg @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oceanBreeze/litecoin.svg b/assets/images/oceanBreeze/litecoin.svg new file mode 100644 index 000000000..f224c429f --- /dev/null +++ b/assets/images/oceanBreeze/litecoin.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oceanBreeze/particl.svg b/assets/images/oceanBreeze/particl.svg new file mode 100644 index 000000000..d15918985 --- /dev/null +++ b/assets/images/oceanBreeze/particl.svg @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oceanBreeze/stack.png b/assets/images/oceanBreeze/stack.png index b59af1608..317c9f775 100644 Binary files a/assets/images/oceanBreeze/stack.png and b/assets/images/oceanBreeze/stack.png differ diff --git a/assets/images/oceanBreeze/stack.svg b/assets/images/oceanBreeze/stack.svg new file mode 100644 index 000000000..43f29e515 --- /dev/null +++ b/assets/images/oceanBreeze/stack.svg @@ -0,0 +1,440 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oceanBreeze/wownero.svg b/assets/images/oceanBreeze/wownero.svg new file mode 100644 index 000000000..812123542 --- /dev/null +++ b/assets/images/oceanBreeze/wownero.svg @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oledBlack/bitcoin.svg b/assets/images/oledBlack/bitcoin.svg new file mode 100644 index 000000000..d3abd0954 --- /dev/null +++ b/assets/images/oledBlack/bitcoin.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oledBlack/bitcoincash.svg b/assets/images/oledBlack/bitcoincash.svg new file mode 100644 index 000000000..6a10cce09 --- /dev/null +++ b/assets/images/oledBlack/bitcoincash.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oledBlack/doge.svg b/assets/images/oledBlack/doge.svg new file mode 100644 index 000000000..2c1d693b4 --- /dev/null +++ b/assets/images/oledBlack/doge.svg @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oledBlack/firo.svg b/assets/images/oledBlack/firo.svg new file mode 100644 index 000000000..6f502205c --- /dev/null +++ b/assets/images/oledBlack/firo.svg @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oledBlack/litecoin.svg b/assets/images/oledBlack/litecoin.svg new file mode 100644 index 000000000..f224c429f --- /dev/null +++ b/assets/images/oledBlack/litecoin.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oledBlack/particl.svg b/assets/images/oledBlack/particl.svg new file mode 100644 index 000000000..d15918985 --- /dev/null +++ b/assets/images/oledBlack/particl.svg @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oledBlack/stack.svg b/assets/images/oledBlack/stack.svg new file mode 100644 index 000000000..43f29e515 --- /dev/null +++ b/assets/images/oledBlack/stack.svg @@ -0,0 +1,440 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/oledBlack/wownero.svg b/assets/images/oledBlack/wownero.svg new file mode 100644 index 000000000..812123542 --- /dev/null +++ b/assets/images/oledBlack/wownero.svg @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/svg/fruitSorbet/persona-easy-1.png b/assets/svg/fruitSorbet/persona-easy-1.png new file mode 100644 index 000000000..f2dd39e2f Binary files /dev/null and b/assets/svg/fruitSorbet/persona-easy-1.png differ diff --git a/assets/svg/fruitSorbet/persona-incognito-1.png b/assets/svg/fruitSorbet/persona-incognito-1.png new file mode 100644 index 000000000..16465fcff Binary files /dev/null and b/assets/svg/fruitSorbet/persona-incognito-1.png differ diff --git a/assets/svg/oceanBreeze/persona-easy-1.png b/assets/svg/oceanBreeze/persona-easy-1.png new file mode 100644 index 000000000..20cafb519 Binary files /dev/null and b/assets/svg/oceanBreeze/persona-easy-1.png differ diff --git a/assets/svg/oceanBreeze/persona-incognito-1.png b/assets/svg/oceanBreeze/persona-incognito-1.png new file mode 100644 index 000000000..8453cfa76 Binary files /dev/null and b/assets/svg/oceanBreeze/persona-incognito-1.png differ diff --git a/lib/exceptions/exchange/unsupported_currency_exception.dart b/lib/exceptions/exchange/unsupported_currency_exception.dart new file mode 100644 index 000000000..9e4430de8 --- /dev/null +++ b/lib/exceptions/exchange/unsupported_currency_exception.dart @@ -0,0 +1,7 @@ +import 'package:stackwallet/exceptions/exchange/exchange_exception.dart'; + +class UnsupportedCurrencyException extends ExchangeException { + UnsupportedCurrencyException(super.message, super.type, this.currency); + + final String currency; +} diff --git a/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart index 816a27cd2..bf479a08c 100644 --- a/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart +++ b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart @@ -1,8 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/providers/ui/color_theme_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/theme/color_theme.dart'; -class CoinImage extends StatelessWidget { +class CoinImage extends ConsumerWidget { const CoinImage({ Key? key, required this.coin, @@ -13,12 +17,30 @@ class CoinImage extends StatelessWidget { final bool isDesktop; @override - Widget build(BuildContext context) { - return Image( - image: AssetImage( - Assets.png.imageFor(coin: coin, context: context), - ), - width: isDesktop ? 324 : MediaQuery.of(context).size.width / 3, - ); + Widget build(BuildContext context, WidgetRef ref) { + final bool isSorbet = ref.read(colorThemeProvider.state).state.themeType == + ThemeType.fruitSorbet; + final bool isForest = + ref.read(colorThemeProvider.state).state.themeType == ThemeType.forest; + + return ((isSorbet || isForest) && + coin != Coin.epicCash && + coin != Coin.monero && + coin != Coin.namecoin) + ? ((isForest && coin != Coin.litecoin && coin != Coin.dogecoin) + ? SvgPicture.asset( + Assets.svg.imageFor(coin: coin, context: context), + width: isDesktop ? 324 : MediaQuery.of(context).size.width, + ) + : Image( + image: AssetImage( + Assets.png.imageFor(coin: coin, context: context), + ))) + : Image( + image: AssetImage( + Assets.png.imageFor(coin: coin, context: context), + ), + width: isDesktop ? 324 : MediaQuery.of(context).size.width / 3, + ); } } diff --git a/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart b/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart index bb17e91ee..aa1683c3f 100644 --- a/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart +++ b/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:isar/isar.dart'; +import 'package:stackwallet/exceptions/exchange/unsupported_currency_exception.dart'; import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; import 'package:stackwallet/models/isar/exchange_cache/pair.dart'; import 'package:stackwallet/pages/buy_view/sub_widgets/crypto_selection_view.dart'; @@ -106,6 +107,10 @@ class _ExchangeCurrencySelectionViewState ); if (cn.value == null) { + if (cn.exception is UnsupportedCurrencyException) { + return currencies; + } + await showDialog( context: context, builder: (context) => StackDialog( @@ -130,11 +135,11 @@ class _ExchangeCurrencySelectionViewState currencies.addAll(cn.value!); } - return currencies; + return _getDistinctCurrenciesFrom(currencies); } Future> _getCurrencies() async { - return ExchangeDataLoadingService.instance.isar.currencies + final currencies = await ExchangeDataLoadingService.instance.isar.currencies .where() .filter() .isFiatEqualTo(false) @@ -150,22 +155,40 @@ class _ExchangeCurrencySelectionViewState .rateTypeEqualTo(SupportedRateType.estimated)) .sortByIsStackCoin() .thenByName() - .distinctByTicker(caseSensitive: false) .findAll(); + + return _getDistinctCurrenciesFrom(currencies); + } + + List _getDistinctCurrenciesFrom(List currencies) { + final List distinctCurrencies = []; + for (final currency in currencies) { + if (!distinctCurrencies.any((e) => e.ticker == currency.ticker)) { + distinctCurrencies.add(currency); + } + } + return distinctCurrencies; } List filter(String text) { - if (text.isEmpty) { - return _currencies; - } - if (widget.pairedTicker == null) { + if (text.isEmpty) { + return _currencies; + } + return _currencies .where((e) => e.name.toLowerCase().contains(text.toLowerCase()) || e.ticker.toLowerCase().contains(text.toLowerCase())) .toList(growable: false); } else { + if (text.isEmpty) { + return _currencies + .where((e) => + e.ticker.toLowerCase() != widget.pairedTicker!.toLowerCase()) + .toList(growable: false); + } + return _currencies .where((e) => e.ticker.toLowerCase() != widget.pairedTicker!.toLowerCase() && diff --git a/lib/pages/paynym/add_new_paynym_follow_view.dart b/lib/pages/paynym/add_new_paynym_follow_view.dart index b5c1ba85e..68473fc7c 100644 --- a/lib/pages/paynym/add_new_paynym_follow_view.dart +++ b/lib/pages/paynym/add_new_paynym_follow_view.dart @@ -445,6 +445,7 @@ class _AddNewPaynymFollowViewState .backgroundAppBar : null, child: PaynymCard( + key: UniqueKey(), label: _searchResult!.nymName, paymentCodeString: _searchResult!.codes.first.code, walletId: widget.walletId, diff --git a/lib/pages/paynym/dialogs/paynym_details_popup.dart b/lib/pages/paynym/dialogs/paynym_details_popup.dart index 729ed5941..c6dedeb39 100644 --- a/lib/pages/paynym/dialogs/paynym_details_popup.dart +++ b/lib/pages/paynym/dialogs/paynym_details_popup.dart @@ -26,6 +26,7 @@ import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; +import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:tuple/tuple.dart'; class PaynymDetailsPopup extends ConsumerStatefulWidget { @@ -102,6 +103,20 @@ class _PaynymDetailsPopupState extends ConsumerState { _showInsufficientFundsInfo = true; }); return; + } catch (e) { + if (mounted) { + canPop = true; + Navigator.of(context).pop(); + } + + await showDialog( + context: context, + builder: (context) => StackOkDialog( + title: "Error", + message: e.toString(), + ), + ); + return; } if (mounted) { diff --git a/lib/pages/stack_privacy_calls.dart b/lib/pages/stack_privacy_calls.dart index 5ec5b881d..474b521d1 100644 --- a/lib/pages/stack_privacy_calls.dart +++ b/lib/pages/stack_privacy_calls.dart @@ -12,6 +12,7 @@ import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/color_theme.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; @@ -299,12 +300,16 @@ class _PrivacyToggleState extends ConsumerState { late bool externalCallsEnabled; late final bool isDesktop; - late final bool usePNG; + late final bool isSorbet; + late final bool isOcean; @override void initState() { isDesktop = Util.isDesktop; - usePNG = ref.read(colorThemeProvider.state).state == "fruitSorbet"; + isSorbet = ref.read(colorThemeProvider.state).state.themeType == + ThemeType.fruitSorbet; + isOcean = ref.read(colorThemeProvider.state).state.themeType == + ThemeType.oceanBreeze; // initial toggle state externalCallsEnabled = widget.externalCallsEnabled; super.initState(); @@ -348,22 +353,25 @@ class _PrivacyToggleState extends ConsumerState { Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - if (isDesktop) - const SizedBox( - height: 10, - ), - // Image.asset( - // // Assets.png.personaEasy, - // ), - SvgPicture.asset( - Assets.svg.personaEasy(context), - width: isDesktop ? 120 : 140, - height: isDesktop ? 120 : 140, - ), - if (isDesktop) - const SizedBox( - height: 12, - ), + // if (isDesktop) + // const SizedBox( + // height: 10, + // ), + (isSorbet || isOcean) + ? Image.asset( + Assets.png.personaEasy(context), + width: 140, + height: 140, + ) + : SvgPicture.asset( + Assets.svg.personaEasy(context), + width: 140, + height: 140, + ), + // if (isDesktop) + // const SizedBox( + // height: 12, + // ), Center( child: Text( "Easy Crypto", diff --git a/lib/pages/wallets_view/sub_widgets/empty_wallets.dart b/lib/pages/wallets_view/sub_widgets/empty_wallets.dart index 7391eca9d..09c6a876f 100644 --- a/lib/pages/wallets_view/sub_widgets/empty_wallets.dart +++ b/lib/pages/wallets_view/sub_widgets/empty_wallets.dart @@ -1,19 +1,26 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart'; +import 'package:stackwallet/providers/ui/color_theme_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/color_theme.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/util.dart'; -class EmptyWallets extends StatelessWidget { +class EmptyWallets extends ConsumerWidget { const EmptyWallets({Key? key}) : super(key: key); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { debugPrint("BUILD: $runtimeType"); final isDesktop = Util.isDesktop; + final bool isSorbet = ref.read(colorThemeProvider.state).state.themeType == + ThemeType.fruitSorbet; + final bool isForest = + ref.read(colorThemeProvider.state).state.themeType == ThemeType.forest; return SafeArea( child: Padding( @@ -29,12 +36,21 @@ class EmptyWallets extends StatelessWidget { const Spacer( flex: 2, ), - Image( - image: AssetImage( - Assets.png.stack(context), - ), - width: isDesktop ? 324 : MediaQuery.of(context).size.width / 3, - ), + (isSorbet || isForest) + ? SvgPicture.asset( + Assets.svg.stack(context), + width: isDesktop + ? 324 + : MediaQuery.of(context).size.width / 3, + ) + : Image( + image: AssetImage( + Assets.png.stack(context), + ), + width: isDesktop + ? 324 + : MediaQuery.of(context).size.width / 3, + ), SizedBox( height: isDesktop ? 30 : 16, ), diff --git a/lib/pages_desktop_specific/settings/settings_menu/advanced_settings/stack_privacy_dialog.dart b/lib/pages_desktop_specific/settings/settings_menu/advanced_settings/stack_privacy_dialog.dart index a2591e57a..cb24fbd6f 100644 --- a/lib/pages_desktop_specific/settings/settings_menu/advanced_settings/stack_privacy_dialog.dart +++ b/lib/pages_desktop_specific/settings/settings_menu/advanced_settings/stack_privacy_dialog.dart @@ -10,6 +10,7 @@ import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/color_theme.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; @@ -18,6 +19,8 @@ import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; +import '../../../../providers/ui/color_theme_provider.dart'; + class StackPrivacyDialog extends ConsumerStatefulWidget { const StackPrivacyDialog({Key? key}) : super(key: key); @@ -149,7 +152,9 @@ class _StackPrivacyDialog extends ConsumerState { Expanded( child: SecondaryButton( label: "Cancel", - onPressed: () {}, + onPressed: () { + Navigator.of(context).pop(); + }, ), ), const SizedBox( @@ -192,7 +197,7 @@ class _StackPrivacyDialog extends ConsumerState { } } -class PrivacyToggle extends StatefulWidget { +class PrivacyToggle extends ConsumerStatefulWidget { const PrivacyToggle({ Key? key, required this.externalCallsEnabled, @@ -203,17 +208,23 @@ class PrivacyToggle extends StatefulWidget { final void Function(bool)? onChanged; @override - State createState() => _PrivacyToggleState(); + ConsumerState createState() => _PrivacyToggleState(); } -class _PrivacyToggleState extends State { +class _PrivacyToggleState extends ConsumerState { late bool externalCallsEnabled; late final bool isDesktop; + late final bool isSorbet; + late final bool isOcean; @override void initState() { isDesktop = Util.isDesktop; + isSorbet = ref.read(colorThemeProvider.state).state.themeType == + ThemeType.fruitSorbet; + isOcean = ref.read(colorThemeProvider.state).state.themeType == + ThemeType.oceanBreeze; // initial toggle state externalCallsEnabled = widget.externalCallsEnabled; super.initState(); @@ -262,11 +273,17 @@ class _PrivacyToggleState extends State { const SizedBox( height: 10, ), - SvgPicture.asset( - Assets.svg.personaEasy(context), - width: 120, - height: 120, - ), + (isSorbet || isOcean) + ? Image.asset( + Assets.png.personaEasy(context), + width: 120, + height: 120, + ) + : SvgPicture.asset( + Assets.svg.personaEasy(context), + width: 120, + height: 120, + ), if (isDesktop) const SizedBox( height: 12, @@ -368,11 +385,17 @@ class _PrivacyToggleState extends State { const SizedBox( height: 10, ), - SvgPicture.asset( - Assets.svg.personaIncognito(context), - width: 120, - height: 120, - ), + (isSorbet || isOcean) + ? Image.asset( + Assets.png.personaIncognito(context), + width: 120, + height: 120, + ) + : SvgPicture.asset( + Assets.svg.personaIncognito(context), + width: 120, + height: 120, + ), if (isDesktop) const SizedBox( height: 12, diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 35bfd2906..bdb6b7add 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -6,7 +6,6 @@ import 'dart:isolate'; import 'package:decimal/decimal.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_libepiccash/epic_cash.dart'; -import 'package:http/http.dart'; import 'package:isar/isar.dart'; import 'package:mutex/mutex.dart'; import 'package:stack_wallet_backup/generate_password.dart'; @@ -37,6 +36,7 @@ import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/stack_file_system.dart'; import 'package:stackwallet/utilities/test_epic_box_connection.dart'; import 'package:tuple/tuple.dart'; +import 'package:websocket_universal/websocket_universal.dart'; const int MINIMUM_CONFIRMATIONS = 10; @@ -462,6 +462,18 @@ class EpicCashWallet extends CoinServiceAPI dynamic message; String receiverAddress = txData['addresss'] as String; + + if (!receiverAddress.startsWith("http://") || + !receiverAddress.startsWith("https://")) { + final decoded = json.decode(epicboxConfig); + bool isEpicboxConnected = await testEpicboxServer( + decoded["epicbox_domain"] as String, + decoded["epicbox_port"] as int); + if (!isEpicboxConnected) { + throw Exception("Failed to send TX : Unable to reach epicbox server"); + } + } + await m.protect(() async { if (receiverAddress.startsWith("http://") || receiverAddress.startsWith("https://")) { @@ -980,22 +992,75 @@ class EpicCashWallet extends CoinServiceAPI return stringConfig; } + Future testEpicboxServer(String host, int port) async { + final websocketConnectionUri = 'wss://$host:$port'; + const connectionOptions = SocketConnectionOptions( + pingIntervalMs: 3000, + timeoutConnectionMs: 4000, + + /// see ping/pong messages in [logEventStream] stream + skipPingMessages: true, + + /// Set this attribute to `true` if do not need any ping/pong + /// messages and ping measurement. Default is `false` + pingRestrictionForce: false, + ); + + final IMessageProcessor textSocketProcessor = + SocketSimpleTextProcessor(); + final textSocketHandler = IWebSocketHandler.createClient( + websocketConnectionUri, + textSocketProcessor, + connectionOptions: connectionOptions, + ); + + // Listening to server responses: + bool isConnected = true; + textSocketHandler.incomingMessagesStream.listen((inMsg) { + Logging.instance.log( + '> webSocket got text message from server: "$inMsg" ' + '[ping: ${textSocketHandler.pingDelayMs}]', + level: LogLevel.Info); + }); + + // Connecting to server: + final isTextSocketConnected = await textSocketHandler.connect(); + if (!isTextSocketConnected) { + // ignore: avoid_print + Logging.instance.log( + 'Connection to [$websocketConnectionUri] failed for some reason!', + level: LogLevel.Error); + isConnected = false; + } + return isConnected; + } + Future getEpicBoxConfig() async { - final storedConfig = + String? storedConfig = await _secureStore.read(key: '${_walletId}_epicboxConfig'); - if (storedConfig != null) { - final decoded = json.decode(storedConfig!); + if (storedConfig == null) { + return json.encode(DefaultNodes.defaultEpicBoxConfig); + } else { + dynamic decoded = json.decode(storedConfig!); final domain = decoded["domain"] ?? "empty"; if (domain != "empty") { - //If we have the old invalid config - update - await _secureStore.write( - key: '${_walletId}_epicboxConfig', - value: DefaultNodes.defaultEpicBoxConfig); + //If we have the old invalid config, use the new default one + // new storage format stores domain under "epicbox_domain", old storage format used "domain" + storedConfig = DefaultNodes.defaultEpicBoxConfig; + decoded = json.decode(storedConfig); } - return await _secureStore.read(key: '${_walletId}_epicboxConfig') ?? - DefaultNodes.defaultEpicBoxConfig; + //Check Epicbox is up before returning it + bool isEpicboxConnected = await testEpicboxServer( + decoded["epicbox_domain"] as String, decoded["epicbox_port"] as int); + + if (!isEpicboxConnected) { + //Default Epicbox is not connected, Defaulting to Europe + storedConfig = json.encode(DefaultNodes.epicBoxConfigEUR); + // TODO test this connection before returning it, iterating through the list of default Epic Box servers + } + + return storedConfig; } - return DefaultNodes.defaultEpicBoxConfig; } Future getRealConfig() async { diff --git a/lib/services/exchange/change_now/change_now_api.dart b/lib/services/exchange/change_now/change_now_api.dart index 99171a62f..cc9a14182 100644 --- a/lib/services/exchange/change_now/change_now_api.dart +++ b/lib/services/exchange/change_now/change_now_api.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:stackwallet/exceptions/exchange/exchange_exception.dart'; import 'package:stackwallet/exceptions/exchange/pair_unavailable_exception.dart'; +import 'package:stackwallet/exceptions/exchange/unsupported_currency_exception.dart'; import 'package:stackwallet/external_api_keys.dart'; import 'package:stackwallet/models/exchange/change_now/cn_exchange_estimate.dart'; import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart'; @@ -49,9 +50,16 @@ class ChangeNowAPI { headers: {'Content-Type': 'application/json'}, ); - final parsed = jsonDecode(response.body); + try { + final parsed = jsonDecode(response.body); - return parsed; + return parsed; + } on FormatException catch (e) { + return { + "error": "Dart format exception", + "message": response.body, + }; + } } catch (e, s) { Logging.instance .log("_makeRequest($uri) threw: $e\n$s", level: LogLevel.Error); @@ -207,7 +215,20 @@ class ChangeNowAPI { try { // json array is expected here - final jsonArray = (await _makeGetRequest(uri)) as List; + + final response = await _makeGetRequest(uri); + + if (response is Map && response["error"] != null) { + return ExchangeResponse( + exception: UnsupportedCurrencyException( + response["message"] as String? ?? response["error"].toString(), + ExchangeExceptionType.generic, + ticker, + ), + ); + } + + final jsonArray = response as List; List currencies = []; try { diff --git a/lib/services/exchange/majestic_bank/majestic_bank_exchange.dart b/lib/services/exchange/majestic_bank/majestic_bank_exchange.dart index fe6216e07..67012ad9b 100644 --- a/lib/services/exchange/majestic_bank/majestic_bank_exchange.dart +++ b/lib/services/exchange/majestic_bank/majestic_bank_exchange.dart @@ -21,6 +21,13 @@ class MajesticBankExchange extends Exchange { static const exchangeName = "Majestic Bank"; + static const kMajesticBankCurrencyNames = { + "BTC": "Bitcoin", + "LTC": "Litecoin", + "WOW": "Wownero", + "XMR": "Monero", + }; + @override Future> createTrade({ required String from, @@ -110,7 +117,8 @@ class MajesticBankExchange extends Exchange { final currency = Currency( exchangeName: MajesticBankExchange.exchangeName, ticker: limit.currency, - name: limit.currency, // todo: get full coin name + name: kMajesticBankCurrencyNames[limit.currency] ?? + limit.currency, // todo: add more names if MB adds more network: "", image: "", isFiat: false, diff --git a/lib/services/mixins/paynym_wallet_interface.dart b/lib/services/mixins/paynym_wallet_interface.dart index 876d863e3..774c7c609 100644 --- a/lib/services/mixins/paynym_wallet_interface.dart +++ b/lib/services/mixins/paynym_wallet_interface.dart @@ -27,6 +27,8 @@ import 'package:tuple/tuple.dart'; const kPaynymDerivePath = "m/47'/0'/0'"; mixin PaynymWalletInterface { + static const String _connectedKeyPrefix = "paynym_connected_"; + // passed in wallet data late final String _walletId; late final String _walletName; @@ -396,135 +398,162 @@ mixin PaynymWalletInterface { int additionalOutputs = 0, List? utxos, }) async { - final amountToSend = _dustLimitP2PKH; - final List availableOutputs = - utxos ?? await _db.getUTXOs(_walletId).findAll(); - final List spendableOutputs = []; - int spendableSatoshiValue = 0; + try { + final amountToSend = _dustLimitP2PKH; + final List availableOutputs = + utxos ?? await _db.getUTXOs(_walletId).findAll(); + final List spendableOutputs = []; + int spendableSatoshiValue = 0; - // Build list of spendable outputs and totaling their satoshi amount - for (var i = 0; i < availableOutputs.length; i++) { - if (availableOutputs[i].isBlocked == false && - availableOutputs[i] - .isConfirmed(await _getChainHeight(), _minConfirms) == - true) { - spendableOutputs.add(availableOutputs[i]); - spendableSatoshiValue += availableOutputs[i].value; + // Build list of spendable outputs and totaling their satoshi amount + for (var i = 0; i < availableOutputs.length; i++) { + if (availableOutputs[i].isBlocked == false && + availableOutputs[i] + .isConfirmed(await _getChainHeight(), _minConfirms) == + true) { + spendableOutputs.add(availableOutputs[i]); + spendableSatoshiValue += availableOutputs[i].value; + } } - } - if (spendableSatoshiValue < amountToSend) { - // insufficient balance - throw InsufficientBalanceException( - "Spendable balance is less than the minimum required for a notification transaction."); - } else if (spendableSatoshiValue == amountToSend) { - // insufficient balance due to missing amount to cover fee - throw InsufficientBalanceException( - "Remaining balance does not cover the network fee."); - } - - // sort spendable by age (oldest first) - spendableOutputs.sort((a, b) => b.blockTime!.compareTo(a.blockTime!)); - - int satoshisBeingUsed = 0; - int outputsBeingUsed = 0; - List utxoObjectsToUse = []; - - for (int i = 0; - satoshisBeingUsed < amountToSend && i < spendableOutputs.length; - i++) { - utxoObjectsToUse.add(spendableOutputs[i]); - satoshisBeingUsed += spendableOutputs[i].value; - outputsBeingUsed += 1; - } - - // add additional outputs if required - for (int i = 0; - i < additionalOutputs && outputsBeingUsed < spendableOutputs.length; - i++) { - utxoObjectsToUse.add(spendableOutputs[outputsBeingUsed]); - satoshisBeingUsed += spendableOutputs[outputsBeingUsed].value; - outputsBeingUsed += 1; - } - - // gather required signing data - final utxoSigningData = await _fetchBuildTxData(utxoObjectsToUse); - - final int vSizeForNoChange = (await _createNotificationTx( - targetPaymentCodeString: targetPaymentCodeString, - utxosToUse: utxoObjectsToUse, - utxoSigningData: utxoSigningData, - change: 0)) - .item2; - - final int vSizeForWithChange = (await _createNotificationTx( - targetPaymentCodeString: targetPaymentCodeString, - utxosToUse: utxoObjectsToUse, - utxoSigningData: utxoSigningData, - change: satoshisBeingUsed - amountToSend)) - .item2; - - // Assume 2 outputs, for recipient and payment code script - int feeForNoChange = _estimateTxFee( - vSize: vSizeForNoChange, - feeRatePerKB: selectedTxFeeRate, - ); - - // Assume 3 outputs, for recipient, payment code script, and change - int feeForWithChange = _estimateTxFee( - vSize: vSizeForWithChange, - feeRatePerKB: selectedTxFeeRate, - ); - - if (_coin == Coin.dogecoin || _coin == Coin.dogecoinTestNet) { - if (feeForNoChange < vSizeForNoChange * 1000) { - feeForNoChange = vSizeForNoChange * 1000; + if (spendableSatoshiValue < amountToSend) { + // insufficient balance + throw InsufficientBalanceException( + "Spendable balance is less than the minimum required for a notification transaction."); + } else if (spendableSatoshiValue == amountToSend) { + // insufficient balance due to missing amount to cover fee + throw InsufficientBalanceException( + "Remaining balance does not cover the network fee."); } - if (feeForWithChange < vSizeForWithChange * 1000) { - feeForWithChange = vSizeForWithChange * 1000; + + // sort spendable by age (oldest first) + spendableOutputs.sort((a, b) => b.blockTime!.compareTo(a.blockTime!)); + + int satoshisBeingUsed = 0; + int outputsBeingUsed = 0; + List utxoObjectsToUse = []; + + for (int i = 0; + satoshisBeingUsed < amountToSend && i < spendableOutputs.length; + i++) { + utxoObjectsToUse.add(spendableOutputs[i]); + satoshisBeingUsed += spendableOutputs[i].value; + outputsBeingUsed += 1; } - } - if (satoshisBeingUsed - amountToSend > feeForNoChange + _dustLimitP2PKH) { - // try to add change output due to "left over" amount being greater than - // the estimated fee + the dust limit - int changeAmount = satoshisBeingUsed - amountToSend - feeForWithChange; + // add additional outputs if required + for (int i = 0; + i < additionalOutputs && outputsBeingUsed < spendableOutputs.length; + i++) { + utxoObjectsToUse.add(spendableOutputs[outputsBeingUsed]); + satoshisBeingUsed += spendableOutputs[outputsBeingUsed].value; + outputsBeingUsed += 1; + } - // check estimates are correct and build notification tx - if (changeAmount >= _dustLimitP2PKH && - satoshisBeingUsed - amountToSend - changeAmount == feeForWithChange) { - var txn = await _createNotificationTx( - targetPaymentCodeString: targetPaymentCodeString, - utxosToUse: utxoObjectsToUse, - utxoSigningData: utxoSigningData, - change: changeAmount, - ); + // gather required signing data + final utxoSigningData = await _fetchBuildTxData(utxoObjectsToUse); - int feeBeingPaid = satoshisBeingUsed - amountToSend - changeAmount; + final int vSizeForNoChange = (await _createNotificationTx( + targetPaymentCodeString: targetPaymentCodeString, + utxosToUse: utxoObjectsToUse, + utxoSigningData: utxoSigningData, + change: 0, + dustLimit: + satoshisBeingUsed, // override amount to get around absurd fees error + )) + .item2; - // make sure minimum fee is accurate if that is being used - if (txn.item2 - feeBeingPaid == 1) { - changeAmount -= 1; - feeBeingPaid += 1; - txn = await _createNotificationTx( + final int vSizeForWithChange = (await _createNotificationTx( + targetPaymentCodeString: targetPaymentCodeString, + utxosToUse: utxoObjectsToUse, + utxoSigningData: utxoSigningData, + change: satoshisBeingUsed - amountToSend, + )) + .item2; + + // Assume 2 outputs, for recipient and payment code script + int feeForNoChange = _estimateTxFee( + vSize: vSizeForNoChange, + feeRatePerKB: selectedTxFeeRate, + ); + + // Assume 3 outputs, for recipient, payment code script, and change + int feeForWithChange = _estimateTxFee( + vSize: vSizeForWithChange, + feeRatePerKB: selectedTxFeeRate, + ); + + if (_coin == Coin.dogecoin || _coin == Coin.dogecoinTestNet) { + if (feeForNoChange < vSizeForNoChange * 1000) { + feeForNoChange = vSizeForNoChange * 1000; + } + if (feeForWithChange < vSizeForWithChange * 1000) { + feeForWithChange = vSizeForWithChange * 1000; + } + } + + if (satoshisBeingUsed - amountToSend > feeForNoChange + _dustLimitP2PKH) { + // try to add change output due to "left over" amount being greater than + // the estimated fee + the dust limit + int changeAmount = satoshisBeingUsed - amountToSend - feeForWithChange; + + // check estimates are correct and build notification tx + if (changeAmount >= _dustLimitP2PKH && + satoshisBeingUsed - amountToSend - changeAmount == + feeForWithChange) { + var txn = await _createNotificationTx( targetPaymentCodeString: targetPaymentCodeString, utxosToUse: utxoObjectsToUse, utxoSigningData: utxoSigningData, change: changeAmount, ); - } - Map transactionObject = { - "hex": txn.item1, - "recipientPaynym": targetPaymentCodeString, - "amount": amountToSend, - "fee": feeBeingPaid, - "vSize": txn.item2, - }; - return transactionObject; - } else { - // something broke during fee estimation or the change amount is smaller - // than the dust limit. Try without change + int feeBeingPaid = satoshisBeingUsed - amountToSend - changeAmount; + + // make sure minimum fee is accurate if that is being used + if (txn.item2 - feeBeingPaid == 1) { + changeAmount -= 1; + feeBeingPaid += 1; + txn = await _createNotificationTx( + targetPaymentCodeString: targetPaymentCodeString, + utxosToUse: utxoObjectsToUse, + utxoSigningData: utxoSigningData, + change: changeAmount, + ); + } + + Map transactionObject = { + "hex": txn.item1, + "recipientPaynym": targetPaymentCodeString, + "amount": amountToSend, + "fee": feeBeingPaid, + "vSize": txn.item2, + }; + return transactionObject; + } else { + // something broke during fee estimation or the change amount is smaller + // than the dust limit. Try without change + final txn = await _createNotificationTx( + targetPaymentCodeString: targetPaymentCodeString, + utxosToUse: utxoObjectsToUse, + utxoSigningData: utxoSigningData, + change: 0, + ); + + int feeBeingPaid = satoshisBeingUsed - amountToSend; + + Map transactionObject = { + "hex": txn.item1, + "recipientPaynym": targetPaymentCodeString, + "amount": amountToSend, + "fee": feeBeingPaid, + "vSize": txn.item2, + }; + return transactionObject; + } + } else if (satoshisBeingUsed - amountToSend >= feeForNoChange) { + // since we already checked if we need to add a change output we can just + // build without change here final txn = await _createNotificationTx( targetPaymentCodeString: targetPaymentCodeString, utxosToUse: utxoObjectsToUse, @@ -542,40 +571,22 @@ mixin PaynymWalletInterface { "vSize": txn.item2, }; return transactionObject; - } - } else if (satoshisBeingUsed - amountToSend >= feeForNoChange) { - // since we already checked if we need to add a change output we can just - // build without change here - final txn = await _createNotificationTx( - targetPaymentCodeString: targetPaymentCodeString, - utxosToUse: utxoObjectsToUse, - utxoSigningData: utxoSigningData, - change: 0, - ); - - int feeBeingPaid = satoshisBeingUsed - amountToSend; - - Map transactionObject = { - "hex": txn.item1, - "recipientPaynym": targetPaymentCodeString, - "amount": amountToSend, - "fee": feeBeingPaid, - "vSize": txn.item2, - }; - return transactionObject; - } else { - // if we get here we do not have enough funds to cover the tx total so we - // check if we have any more available outputs and try again - if (spendableOutputs.length > outputsBeingUsed) { - return prepareNotificationTx( - selectedTxFeeRate: selectedTxFeeRate, - targetPaymentCodeString: targetPaymentCodeString, - additionalOutputs: additionalOutputs + 1, - ); } else { - throw InsufficientBalanceException( - "Remaining balance does not cover the network fee."); + // if we get here we do not have enough funds to cover the tx total so we + // check if we have any more available outputs and try again + if (spendableOutputs.length > outputsBeingUsed) { + return prepareNotificationTx( + selectedTxFeeRate: selectedTxFeeRate, + targetPaymentCodeString: targetPaymentCodeString, + additionalOutputs: additionalOutputs + 1, + ); + } else { + throw InsufficientBalanceException( + "Remaining balance does not cover the network fee."); + } } + } catch (e) { + rethrow; } } @@ -586,85 +597,109 @@ mixin PaynymWalletInterface { required List utxosToUse, required Map utxoSigningData, required int change, + int? dustLimit, }) async { - final targetPaymentCode = - PaymentCode.fromPaymentCode(targetPaymentCodeString, _network); - final myCode = await getPaymentCode(DerivePathType.bip44); + try { + final targetPaymentCode = + PaymentCode.fromPaymentCode(targetPaymentCodeString, _network); + final myCode = await getPaymentCode(DerivePathType.bip44); - final utxo = utxosToUse.first; - final txPoint = utxo.txid.fromHex.toList(); - final txPointIndex = utxo.vout; + final utxo = utxosToUse.first; + final txPoint = utxo.txid.fromHex.toList(); + final txPointIndex = utxo.vout; - final rev = Uint8List(txPoint.length + 4); - Util.copyBytes(Uint8List.fromList(txPoint), 0, rev, 0, txPoint.length); - final buffer = rev.buffer.asByteData(); - buffer.setUint32(txPoint.length, txPointIndex, Endian.little); + final rev = Uint8List(txPoint.length + 4); + Util.copyBytes(Uint8List.fromList(txPoint), 0, rev, 0, txPoint.length); + final buffer = rev.buffer.asByteData(); + buffer.setUint32(txPoint.length, txPointIndex, Endian.little); - final myKeyPair = utxoSigningData[utxo.txid]["keyPair"] as btc_dart.ECPair; + final myKeyPair = + utxoSigningData[utxo.txid]["keyPair"] as btc_dart.ECPair; - final S = SecretPoint( - myKeyPair.privateKey!, - targetPaymentCode.notificationPublicKey(), - ); + final S = SecretPoint( + myKeyPair.privateKey!, + targetPaymentCode.notificationPublicKey(), + ); - final blindingMask = PaymentCode.getMask(S.ecdhSecret(), rev); + final blindingMask = PaymentCode.getMask(S.ecdhSecret(), rev); - final blindedPaymentCode = PaymentCode.blind( - payload: myCode.getPayload(), - mask: blindingMask, - unBlind: false, - ); + final blindedPaymentCode = PaymentCode.blind( + payload: myCode.getPayload(), + mask: blindingMask, + unBlind: false, + ); - final opReturnScript = bscript.compile([ - (op.OPS["OP_RETURN"] as int), - blindedPaymentCode, - ]); + final opReturnScript = bscript.compile([ + (op.OPS["OP_RETURN"] as int), + blindedPaymentCode, + ]); - // build a notification tx - final txb = btc_dart.TransactionBuilder(network: _network); - txb.setVersion(1); + // build a notification tx + final txb = btc_dart.TransactionBuilder(network: _network); + txb.setVersion(1); - txb.addInput( - utxo.txid, - txPointIndex, - null, - utxoSigningData[utxo.txid]["output"] as Uint8List, - ); + txb.addInput( + utxo.txid, + txPointIndex, + null, + utxoSigningData[utxo.txid]["output"] as Uint8List, + ); - // todo: modify address once segwit support is in our bip47 - txb.addOutput( - targetPaymentCode.notificationAddressP2PKH(), _dustLimitP2PKH); - txb.addOutput(opReturnScript, 0); + // add rest of possible inputs + for (var i = 1; i < utxosToUse.length; i++) { + final utxo = utxosToUse[i]; + txb.addInput( + utxo.txid, + utxo.vout, + null, + utxoSigningData[utxo.txid]["output"] as Uint8List, + ); + } - // TODO: add possible change output and mark output as dangerous - if (change > 0) { - // generate new change address if current change address has been used - await _checkChangeAddressForTransactions(); - final String changeAddress = await _getCurrentChangeAddress(); - txb.addOutput(changeAddress, change); - } + // todo: modify address once segwit support is in our bip47 + txb.addOutput( + targetPaymentCode.notificationAddressP2PKH(), + dustLimit ?? _dustLimitP2PKH, + ); + txb.addOutput(opReturnScript, 0); - txb.sign( - vin: 0, - keyPair: myKeyPair, - witnessValue: utxo.value, - witnessScript: utxoSigningData[utxo.txid]["redeemScript"] as Uint8List?, - ); + // TODO: add possible change output and mark output as dangerous + if (change > 0) { + // generate new change address if current change address has been used + await _checkChangeAddressForTransactions(); + final String changeAddress = await _getCurrentChangeAddress(); + txb.addOutput(changeAddress, change); + } - // sign rest of possible inputs - for (var i = 1; i < utxosToUse.length; i++) { - final txid = utxosToUse[i].txid; txb.sign( - vin: i, - keyPair: utxoSigningData[txid]["keyPair"] as btc_dart.ECPair, - witnessValue: utxosToUse[i].value, + vin: 0, + keyPair: myKeyPair, + witnessValue: utxo.value, witnessScript: utxoSigningData[utxo.txid]["redeemScript"] as Uint8List?, ); + + // sign rest of possible inputs + for (var i = 1; i < utxosToUse.length; i++) { + final txid = utxosToUse[i].txid; + txb.sign( + vin: i, + keyPair: utxoSigningData[txid]["keyPair"] as btc_dart.ECPair, + witnessValue: utxosToUse[i].value, + witnessScript: + utxoSigningData[utxo.txid]["redeemScript"] as Uint8List?, + ); + } + + final builtTx = txb.build(); + + return Tuple2(builtTx.toHex(), builtTx.virtualSize()); + } catch (e, s) { + Logging.instance.log( + "_createNotificationTx(): $e\n$s", + level: LogLevel.Error, + ); + rethrow; } - - final builtTx = txb.build(); - - return Tuple2(builtTx.toHex(), builtTx.virtualSize()); } Future broadcastNotificationTx( @@ -694,8 +729,41 @@ mixin PaynymWalletInterface { } } + // Future _checkHasConnectedCache(String paymentCodeString) async { + // final value = await _secureStorage.read( + // key: "$_connectedKeyPrefix$paymentCodeString"); + // if (value == null) { + // return null; + // } else { + // final int rawBool = int.parse(value); + // return rawBool > 0; + // } + // } + // + // Future _setConnectedCache( + // String paymentCodeString, bool hasConnected) async { + // await _secureStorage.write( + // key: "$_connectedKeyPrefix$paymentCodeString", + // value: hasConnected ? "1" : "0"); + // } + // TODO optimize Future hasConnected(String paymentCodeString) async { + // final didConnect = await _checkHasConnectedCache(paymentCodeString); + // if (didConnect == true) { + // return true; + // } + // + // final keys = await lookupKey(paymentCodeString); + // + // final tx = await _db + // .getTransactions(_walletId) + // .filter() + // .subTypeEqualTo(TransactionSubType.bip47Notification).and() + // .address((q) => + // q.anyOf(keys, (q, e) => q.otherDataEqualTo(e))) + // .findAll(); + final myNotificationAddress = await getMyNotificationAddress(DerivePathTypeExt.primaryFor(_coin)); @@ -706,29 +774,32 @@ mixin PaynymWalletInterface { .findAll(); for (final tx in txns) { - // quick check that may cause problems? - if (tx.address.value?.value == myNotificationAddress.value) { - return true; - } + if (tx.type == TransactionType.incoming && + tx.address.value?.value == myNotificationAddress.value) { + final unBlindedPaymentCode = await unBlindedPaymentCodeFromTransaction( + transaction: tx, + myNotificationAddress: myNotificationAddress, + ); - final unBlindedPaymentCode = await unBlindedPaymentCodeFromTransaction( - transaction: tx, - myNotificationAddress: myNotificationAddress, - ); - - if (paymentCodeString == unBlindedPaymentCode.toString()) { - return true; - } - - if (tx.address.value?.otherData != null) { - final code = await paymentCodeStringByKey(tx.address.value!.otherData!); - if (code == paymentCodeString) { + if (unBlindedPaymentCode != null && + paymentCodeString == unBlindedPaymentCode.toString()) { + // await _setConnectedCache(paymentCodeString, true); return true; } + } else if (tx.type == TransactionType.outgoing) { + if (tx.address.value?.otherData != null) { + final code = + await paymentCodeStringByKey(tx.address.value!.otherData!); + if (code == paymentCodeString) { + // await _setConnectedCache(paymentCodeString, true); + return true; + } + } } } // otherwise return no + // await _setConnectedCache(paymentCodeString, false); return false; } diff --git a/lib/utilities/assets.dart b/lib/utilities/assets.dart index d746984cf..5dee99bf1 100644 --- a/lib/utilities/assets.dart +++ b/lib/utilities/assets.dart @@ -99,6 +99,9 @@ class _SVG { String personaEasy(BuildContext context) => "assets/svg/${Theme.of(context).extension()!.themeType.name}/persona-easy-1.svg"; + String stack(BuildContext context) => + "assets/images/${Theme.of(context).extension()!.themeType.name}/stack.svg"; + String get themeFruit => "assets/svg/fruit-sorbet-theme.svg"; String get themeForest => "assets/svg/forest-theme.svg"; String get themeOledBlack => "assets/svg/oled-black-theme.svg"; @@ -209,6 +212,7 @@ class _SVG { String get ellipse1 => "assets/svg/Ellipse-43.svg"; String get ellipse2 => "assets/svg/Ellipse-42.svg"; + // small icons String get bitcoin => "assets/svg/coin_icons/Bitcoin.svg"; String get litecoin => "assets/svg/coin_icons/Litecoin.svg"; String get bitcoincash => "assets/svg/coin_icons/Bitcoincash.svg"; @@ -267,6 +271,59 @@ class _SVG { return dogecoinTestnet; } } + + // big icons + String bitcoinImage(BuildContext context) => + "assets/images/${Theme.of(context).extension()!.themeType.name}/bitcoin.svg"; + String bitcoincashImage(BuildContext context) => + "assets/images/${Theme.of(context).extension()!.themeType.name}/bitcoincash.svg"; + String dogecoinImage(BuildContext context) => + "assets/images/${Theme.of(context).extension()!.themeType.name}/doge.svg"; + // String get epicCashImage => "assets/images/fruitSorbet/epic-cash.svg"; + String firoImage(BuildContext context) => + "assets/images/${Theme.of(context).extension()!.themeType.name}/firo.svg"; + String litecoinImage(BuildContext context) => + "assets/images/${Theme.of(context).extension()!.themeType.name}/litecoin.svg"; + // String get moneroImage => "assets/images/fruitSorbet/monero.svg"; + String wowneroImage(BuildContext context) => + "assets/images/${Theme.of(context).extension()!.themeType.name}/wownero.svg"; + // String get namecoinImage => "assets/images/fruitSorbet/Namecoin.svg"; + String particlImage(BuildContext context) => + "assets/images/${Theme.of(context).extension()!.themeType.name}/particl.svg"; + + String imageFor({required BuildContext context, required Coin coin}) { + switch (coin) { + case Coin.bitcoin: + return bitcoinImage(context); + case Coin.litecoin: + case Coin.litecoinTestNet: + return litecoinImage(context); + case Coin.bitcoincash: + return bitcoincashImage(context); + case Coin.dogecoin: + return dogecoinImage(context); + case Coin.epicCash: + return epicCash; + case Coin.firo: + return firoImage(context); + case Coin.monero: + return monero; + case Coin.wownero: + return wowneroImage(context); + case Coin.namecoin: + return namecoin; + case Coin.particl: + return particlImage(context); + case Coin.bitcoinTestNet: + return bitcoinImage(context); + case Coin.bitcoincashTestnet: + return bitcoincashImage(context); + case Coin.firoTestNet: + return firoImage(context); + case Coin.dogecoinTestNet: + return dogecoinImage(context); + } + } } class _PNG { @@ -298,6 +355,11 @@ class _PNG { String particl(BuildContext context) => "assets/images/${Theme.of(context).extension()!.themeType.name}/particl.png"; + String personaIncognito(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/persona-incognito-1.png"; + String personaEasy(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/persona-easy-1.png"; + String get glasses => "assets/images/glasses.png"; String get glassesHidden => "assets/images/glasses-hidden.png"; diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart index 6e8cc53cb..3348089a3 100644 --- a/lib/utilities/default_nodes.dart +++ b/lib/utilities/default_nodes.dart @@ -262,4 +262,11 @@ abstract class DefaultNodes { "epicbox_protocol_unsecure": false, "epicbox_address_index": 0, }); + + static final String epicBoxConfigEUR = jsonEncode({ + "epicbox_domain": "epicbox.fastepic.eu", + "epicbox_port": 443, + "epicbox_protocol_unsecure": false, + "epicbox_address_index": 0, + }); } diff --git a/lib/utilities/text_styles.dart b/lib/utilities/text_styles.dart index 11a1c3a97..6ff8cdaf1 100644 --- a/lib/utilities/text_styles.dart +++ b/lib/utilities/text_styles.dart @@ -990,7 +990,7 @@ class STextStyles { ); case ThemeType.oledBlack: return GoogleFonts.inter( - color: _theme(context).infoItemIcons, + color: _theme(context).checkboxBGChecked, fontWeight: FontWeight.w500, fontSize: 14, ); diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 7c5023a1c..4f69a784b 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -13,9 +13,9 @@ import flutter_local_notifications import flutter_secure_storage_macos import isar_flutter_libs import package_info_plus_macos -import path_provider_macos +import path_provider_foundation import share_plus -import shared_preferences_macos +import shared_preferences_foundation import stack_wallet_backup import url_launcher_macos import wakelock_macos diff --git a/pubspec.lock b/pubspec.lock index 12902104f..349ab50df 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -35,7 +35,7 @@ packages: name: app_settings url: "https://pub.dartlang.org" source: hosted - version: "4.1.8" + version: "4.2.0" archive: dependency: transitive description: @@ -49,7 +49,7 @@ packages: name: args url: "https://pub.dartlang.org" source: hosted - version: "2.3.1" + version: "2.4.0" asn1lib: dependency: transitive description: @@ -70,7 +70,7 @@ packages: name: barcode_scan2 url: "https://pub.dartlang.org" source: hosted - version: "4.2.1" + version: "4.2.3" bech32: dependency: "direct main" description: @@ -100,8 +100,8 @@ packages: dependency: "direct main" description: path: "." - ref: "7b7c0b9284e7457f40dc60ea4420d8badf1aed39" - resolved-ref: "7b7c0b9284e7457f40dc60ea4420d8badf1aed39" + ref: "48dd65f88822fba8543826274f6d51c17f735f93" + resolved-ref: "48dd65f88822fba8543826274f6d51c17f735f93" url: "https://github.com/cypherstack/bip47.git" source: git version: "1.0.0" @@ -192,7 +192,7 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.4.2" + version: "8.4.3" characters: dependency: transitive description: @@ -206,7 +206,7 @@ packages: name: checked_yaml url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.2" cli_util: dependency: transitive description: @@ -227,7 +227,7 @@ packages: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "4.3.0" + version: "4.4.0" collection: dependency: transitive description: @@ -262,7 +262,7 @@ packages: name: connectivity_plus_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.2.3" + version: "1.2.4" connectivity_plus_web: dependency: transitive description: @@ -297,7 +297,7 @@ packages: name: cross_file url: "https://pub.dartlang.org" source: hosted - version: "0.3.3+2" + version: "0.3.3+4" crypto: dependency: "direct main" description: @@ -311,7 +311,7 @@ packages: name: cryptography url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.1.1" csslib: dependency: transitive description: @@ -493,7 +493,7 @@ packages: name: file_picker url: "https://pub.dartlang.org" source: hosted - version: "5.2.3" + version: "5.2.5" fixnum: dependency: transitive description: @@ -587,7 +587,7 @@ packages: name: flutter_native_splash url: "https://pub.dartlang.org" source: hosted - version: "2.2.9" + version: "2.2.16" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -622,7 +622,7 @@ packages: name: flutter_secure_storage_linux url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.1.3" flutter_secure_storage_macos: dependency: transitive description: @@ -777,7 +777,7 @@ packages: name: image url: "https://pub.dartlang.org" source: hosted - version: "3.2.2" + version: "3.3.0" import_sorter: dependency: "direct dev" description: @@ -803,7 +803,7 @@ packages: name: io url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.4" isar: dependency: "direct main" description: @@ -838,7 +838,7 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.7.0" + version: "4.8.0" jsonrpc2: dependency: "direct main" description: @@ -860,13 +860,6 @@ packages: relative: true source: path version: "0.0.1" - lint: - dependency: transitive - description: - name: lint - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" lints: dependency: transitive description: @@ -887,14 +880,14 @@ packages: name: logging url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" lottie: dependency: "direct main" description: name: lottie url: "https://pub.dartlang.org" source: hosted - version: "1.4.2" + version: "1.4.3" matcher: dependency: transitive description: @@ -922,14 +915,14 @@ packages: name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.4" mobx: dependency: transitive description: name: mobx url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "2.1.4" mockingjay: dependency: "direct dev" description: @@ -1048,7 +1041,7 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.0.12" path_provider_android: dependency: transitive description: @@ -1056,27 +1049,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.22" - path_provider_ios: + path_provider_foundation: dependency: transitive description: - name: path_provider_ios + name: path_provider_foundation url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.1.1" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.7" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.6" + version: "2.1.8" path_provider_platform_interface: dependency: transitive description: @@ -1132,7 +1118,7 @@ packages: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" + version: "5.1.0" platform: dependency: transitive description: @@ -1244,7 +1230,7 @@ packages: name: share_plus url: "https://pub.dartlang.org" source: hosted - version: "6.3.0" + version: "6.3.1" share_plus_platform_interface: dependency: transitive description: @@ -1258,35 +1244,28 @@ packages: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "2.0.15" + version: "2.0.17" shared_preferences_android: dependency: transitive description: name: shared_preferences_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.14" - shared_preferences_ios: + version: "2.0.15" + shared_preferences_foundation: dependency: transitive description: - name: shared_preferences_ios + name: shared_preferences_foundation url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.3" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" - shared_preferences_macos: - dependency: transitive - description: - name: shared_preferences_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" + version: "2.1.3" shared_preferences_platform_interface: dependency: transitive description: @@ -1307,7 +1286,7 @@ packages: name: shared_preferences_windows url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.3" shelf: dependency: transitive description: @@ -1368,7 +1347,7 @@ packages: name: source_maps url: "https://pub.dartlang.org" source: hosted - version: "0.10.10" + version: "0.10.12" source_span: dependency: transitive description: @@ -1468,7 +1447,7 @@ packages: name: time url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" timezone: dependency: transitive description: @@ -1482,14 +1461,14 @@ packages: name: timing url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" tint: dependency: transitive description: name: tint url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.1" toast: dependency: "direct main" description: @@ -1517,42 +1496,42 @@ packages: name: universal_io url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.2.0" url_launcher: dependency: "direct main" description: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "6.1.7" + version: "6.1.9" url_launcher_android: dependency: transitive description: name: url_launcher_android url: "https://pub.dartlang.org" source: hosted - version: "6.0.22" + version: "6.0.23" url_launcher_ios: dependency: transitive description: name: url_launcher_ios url: "https://pub.dartlang.org" source: hosted - version: "6.0.17" + version: "6.1.0" url_launcher_linux: dependency: transitive description: name: url_launcher_linux url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" url_launcher_macos: dependency: transitive description: name: url_launcher_macos url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" url_launcher_platform_interface: dependency: transitive description: @@ -1566,14 +1545,14 @@ packages: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.13" + version: "2.0.14" url_launcher_windows: dependency: transitive description: name: url_launcher_windows url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.3" uuid: dependency: "direct main" description: @@ -1643,7 +1622,7 @@ packages: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.0" webdriver: dependency: transitive description: @@ -1658,13 +1637,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + websocket_universal: + dependency: "direct main" + description: + name: websocket_universal + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.1" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "3.1.2" + version: "3.1.3" window_size: dependency: "direct main" description: @@ -1680,7 +1666,7 @@ packages: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.2.0+2" + version: "0.2.0+3" xml: dependency: transitive description: @@ -1711,4 +1697,4 @@ packages: version: "1.0.0" sdks: dart: ">=2.18.5 <3.0.0" - flutter: ">=3.0.1" + flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml index 46f6364a4..9332db35d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ description: Stack Wallet # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.5.40+127 +version: 1.5.43+130 environment: sdk: ">=2.17.0 <3.0.0" @@ -21,6 +21,7 @@ dependencies: sdk: flutter ffi: ^2.0.1 mutex: ^3.0.0 + websocket_universal: ^0.5.1 lelantus: path: ./crypto_plugins/flutter_liblelantus diff --git a/test/services/change_now/change_now_test.dart b/test/services/change_now/change_now_test.dart index 9fb27e0f1..f79cbcd4d 100644 --- a/test/services/change_now/change_now_test.dart +++ b/test/services/change_now/change_now_test.dart @@ -121,7 +121,8 @@ void main() { final result = await ChangeNowAPI.instance.getAvailableCurrencies(); - expect(result.exception!.type, ExchangeExceptionType.generic); + expect( + result.exception!.type, ExchangeExceptionType.serializeResponseError); expect(result.value == null, true); }); }); @@ -263,7 +264,8 @@ void main() { apiKey: "testAPIKEY", ); - expect(result.exception!.type, ExchangeExceptionType.generic); + expect( + result.exception!.type, ExchangeExceptionType.serializeResponseError); expect(result.value == null, true); }); }); @@ -470,7 +472,8 @@ void main() { apiKey: "testAPIKEY", ); - expect(result.exception!.type, ExchangeExceptionType.generic); + expect( + result.exception!.type, ExchangeExceptionType.serializeResponseError); expect(result.value == null, true); }); }); @@ -721,7 +724,8 @@ void main() { apiKey: "testAPIKEY", ); - expect(result.exception!.type, ExchangeExceptionType.generic); + expect( + result.exception!.type, ExchangeExceptionType.serializeResponseError); expect(result.value == null, true); }); }); @@ -779,7 +783,8 @@ void main() { final result = await ChangeNowAPI.instance.getAvailableFloatingRatePairs(); - expect(result.exception!.type, ExchangeExceptionType.generic); + expect( + result.exception!.type, ExchangeExceptionType.serializeResponseError); expect(result.value == null, true); }); });