Rebase node-sqlite-migration onto dev

Squashed migration of node Hive→SQLite, default-node handling, isPow/proxy support, arbitrum node updates, and related fixes. Replays node-sqlite-migration on top of current dev without the amount-refactor merge that the original branch carried. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Omar committed May 26, 2026 at 17:04 UTC ac05166e956ba09e242144a31a96670aea3f382d
72 files changed +1201 -1052
assets/arbitrum_node_list.yml
+5 -2
@@ -1,12 +1,15 @@
1 -
2 uri: arbitrum.nownodes.io
3 - is_default: true
3 useSSL: true
4 isEnabledForAutoSwitching: true
5 + label: "NOWNodes"
6 -
7 uri: arbitrum.drpc.org
8 useSSL: true
9 + label: "dRPC"
10 -
11 uri: arbitrum-one-rpc.publicnode.com
12 useSSL: true
12 - isEnabledForAutoSwitching: true
\ No newline at end of file
13 + isDefault: true
14 + isEnabledForAutoSwitching: true
15 + label: "PublicNode"
\ No newline at end of file
assets/base_node_list.yml
+6 -2
@@ -1,15 +1,19 @@
1 -
2 uri: base.nownodes.io
3 + isDefault: true
4 useSSL: true
5 isEnabledForAutoSwitching: true
6 + label: "NOWNodes"
7 -
8 uri: base.llamarpc.com
9 useSSL: true
10 + label: "LlamaNodes"
11 -
12 uri: base-rpc.publicnode.com
10 - is_default: true
13 useSSL: true
14 isEnabledForAutoSwitching: true
15 + label: "PublicNode"
16 -
17 uri: 1rpc.io/base
15 - useSSL: true
\ No newline at end of file
18 + useSSL: true
19 + label: "1RPC"
\ No newline at end of file
assets/bitcoin_cash_electrum_server_list.yml
+3 -4
@@ -1,12 +1,11 @@
1 -
2 uri: bitcoincash.stackwallet.com:50002
3 - is_default: true
3 + isDefault: true
4 useSSL: true
5 isEnabledForAutoSwitching: true
6 + label: "Stack Wallet"
7 -
8 uri: bch.aftrek.org:50002
9 useSSL: true
10 isEnabledForAutoSwitching: true
10 --
11 - uri: node.minisatoshi.cash:50002
12 - useSSL: true
11 + label: "Aftrek"
assets/bitcoin_electrum_server_list.yml
+7
@@ -2,14 +2,21 @@
2 uri: btc-electrum.cakewallet.com:50002
3 useSSL: true
4 isDefault: true
5 + isOfficial: true
6 isEnabledForAutoSwitching: true
7 + label: "Cake Wallet Electrum"
8 -
9 uri: electrs.cakewallet.com:50001
10 + isOfficial: true
11 + label: "Cake Wallet Electrs"
12 -
13 uri: fulcrum.sethforprivacy.com:50002
14 useSSL: true
15 isEnabledForAutoSwitching: true
16 + label: "Seth For Privacy"
17 -
18 uri: electrum.cakewallet.com:50002
19 + isOfficial: true
20 useSSL: true
21 isEnabledForAutoSwitching: true
22 + label: "Cake Wallet (Legacy)"
assets/bsc_node_list.yml
+7
@@ -3,26 +3,33 @@
3 useSSL: true
4 isDefault: true
5 isEnabledForAutoSwitching: true
6 + label: "BNBChain"
7 -
8 uri: bsc-dataseed2.bnbchain.org
9 useSSL: true
10 isEnabledForAutoSwitching: true
11 + label: "BNBChain #2"
12 -
13 uri: bsc-dataseed.nariox.org
14 useSSL: true
15 isEnabledForAutoSwitching: true
16 + label: "Nariox"
17 -
18 uri: bsc-dataseed.defibit.io
19 useSSL: true
20 isEnabledForAutoSwitching: true
21 + label: "DeFibit"
22 -
23 uri: bsc-dataseed.ninicoin.io
24 useSSL: true
25 isEnabledForAutoSwitching: true
26 + label: "NiniCoin"
27 -
28 uri: bsc.nodereal.io
29 useSSL: true
30 isEnabledForAutoSwitching: true
31 + label: "NodeReal"
32 -
33 uri: bsc-dataseed-public.bnbchain.org
34 useSSL: true
35 + label: "BNBChain Public"
\ No newline at end of file
assets/decred_node_list.yml
+4 -2
@@ -1,8 +1,10 @@
1 -
2 uri: default-spv-nodes
3 - is_default: true
3 + isDefault: true
4 isEnabledForAutoSwitching: true
5 + label: "Decred"
6 -
7 uri: dcrd.sethforprivacy.com:9108
8 useSSL: true
8 - isEnabledForAutoSwitching: true
\ No newline at end of file
9 + isEnabledForAutoSwitching: true
10 + label: "Seth For Privacy"
\ No newline at end of file
assets/dogecoin_electrum_server_list.yml
+5 -2
@@ -1,12 +1,15 @@
1 -
2 uri: dogecoin.stackwallet.com:50022
3 - is_default: true
3 + isDefault: true
4 useSSL: true
5 isEnabledForAutoSwitching: true
6 + label: "Stack Wallet"
7 -
8 uri: doge.aftrek.org:50002
9 useSSL: true
10 isEnabledForAutoSwitching: true
11 + label: "Aftrek"
12 -
13 uri: electrum1.cipig.net:20060
12 - useSSL: true
\ No newline at end of file
14 + useSSL: true
15 + label: "Cipig"
\ No newline at end of file
assets/ethereum_server_list.yml
+5 -2
@@ -3,18 +3,21 @@
3 useSSL: true
4 isDefault: true
5 isEnabledForAutoSwitching: true
6 + label: "PublicNode"
7 -
8 uri: eth.llamarpc.com
9 useSSL: true
10 + label: "LlamaNodes"
11 -
12 uri: rpc.flashbots.net
13 useSSL: true
14 + label: "Flashbots"
15 -
16 uri: eth-mainnet.public.blastapi.io
17 useSSL: true
18 + label: "Blast"
19 -
20 uri: eth.nownodes.io
21 useSSL: true
22 isEnabledForAutoSwitching: true
19 --
20 - uri: ethereum.publicnode.com
\ No newline at end of file
23 + label: "NOWNodes"
\ No newline at end of file
assets/haven_node_list.yml
+1 -1
@@ -1,4 +1,4 @@
1 -
2 uri: nodes.havenprotocol.org:443
3 useSSL: true
4 - is_default: true
\ No newline at end of file
4 + isDefault: true
\ No newline at end of file
assets/lightning_deposit_help.svg deleted
-99
@@ -1,99 +0,0 @@
1 -<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
2 - <g clip-path="url(#clip0_14800_609868)">
3 - <g opacity="0.5">
4 - <path d="M65.6689 41.3975C61.2164 59.2548 43.128 70.1225 25.2667 65.6694C7.41273 61.2173 -3.45614 43.1298 0.998503 25.2735C5.44898 7.41416 23.5374 -3.45459 41.3934 0.997495C59.2537 5.44958 70.1215 23.5392 65.6689 41.3975Z" fill="url(#paint0_linear_14800_609868)"/>
5 - <path d="M65.6689 41.3975C61.2164 59.2548 43.128 70.1225 25.2667 65.6694C7.41273 61.2173 -3.45614 43.1298 0.998503 25.2735C5.44898 7.41416 23.5374 -3.45459 41.3934 0.997495C59.2537 5.44958 70.1215 23.5392 65.6689 41.3975Z" fill="url(#paint1_linear_14800_609868)"/>
6 - <path d="M0.998503 25.2735C5.44902 7.41421 23.5374 -3.45458 41.3934 0.997489C59.2536 5.44957 70.1214 23.5392 65.669 41.3975L65.5622 41.8149C60.9703 59.2852 43.2701 69.9194 25.6853 65.7709L25.2667 65.6693C7.41273 61.2173 -3.45614 43.1298 0.998503 25.2735ZM41.0708 2.29124C23.9295 -1.9826 6.56484 8.45112 2.29239 25.5959V25.5964C-1.98393 42.7381 8.44993 60.1016 25.5892 64.3756C42.7359 68.6506 60.1007 58.2178 64.3751 41.0751C68.6495 23.9311 58.2162 6.56514 41.0708 2.29124Z" fill="url(#paint2_linear_14800_609868)"/>
7 - <path d="M0.998503 25.2735C5.44902 7.41421 23.5374 -3.45458 41.3934 0.997489C59.2536 5.44957 70.1214 23.5392 65.669 41.3975L65.5622 41.8149C60.9703 59.2852 43.2701 69.9194 25.6853 65.7709L25.2667 65.6693C7.41273 61.2173 -3.45614 43.1298 0.998503 25.2735ZM41.0708 2.29124C23.9295 -1.9826 6.56484 8.45112 2.29239 25.5959V25.5964C-1.98393 42.7381 8.44993 60.1016 25.5892 64.3756C42.7359 68.6506 60.1007 58.2178 64.3751 41.0751C68.6495 23.9311 58.2162 6.56514 41.0708 2.29124Z" fill="url(#paint3_linear_14800_609868)"/>
8 - <path d="M0.998503 25.2735C5.44902 7.41421 23.5374 -3.45458 41.3934 0.997489C59.2536 5.44957 70.1214 23.5392 65.669 41.3975L65.5622 41.8149C60.9703 59.2852 43.2701 69.9194 25.6853 65.7709L25.2667 65.6693C7.41273 61.2173 -3.45614 43.1298 0.998503 25.2735ZM41.0708 2.29124C23.9295 -1.9826 6.56484 8.45112 2.29239 25.5959V25.5964C-1.98393 42.7381 8.44993 60.1016 25.5892 64.3756C42.7359 68.6506 60.1007 58.2178 64.3751 41.0751C68.6495 23.9311 58.2162 6.56514 41.0708 2.29124Z" fill="url(#paint4_linear_14800_609868)"/>
9 - <path d="M48.0289 30.1837C48.6924 25.7482 45.3154 23.3639 40.6977 21.7732L42.1956 15.7649L38.5383 14.8535L37.0799 20.7035C36.1185 20.4639 35.131 20.2378 34.1497 20.0139L35.6185 14.1253L31.9633 13.2139L30.4643 19.2201C29.6685 19.0389 28.8872 18.8597 28.1289 18.6712L28.1331 18.6524L23.0893 17.393L22.1164 21.2993C22.1164 21.2993 24.8299 21.9212 24.7727 21.9597C26.2539 22.3295 26.5216 23.3097 26.4768 24.0868L24.7706 30.9316C24.8727 30.9576 25.0049 30.9951 25.1508 31.0534C25.0289 31.0232 24.8987 30.9899 24.7643 30.9576L22.3727 40.5462C22.1914 40.9962 21.732 41.6712 20.6966 41.4149C20.7331 41.468 18.0383 40.7514 18.0383 40.7514L16.2227 44.9378L20.982 46.1243C21.8674 46.3462 22.7352 46.5784 23.5893 46.7972L22.0758 52.8743L25.7289 53.7857L27.2279 47.7732C28.2258 48.0441 29.1945 48.2941 30.1424 48.5295L28.6487 54.5139L32.306 55.4253L33.8195 49.3597C40.056 50.5399 44.7456 50.0639 46.7195 44.4232C48.3102 39.8816 46.6404 37.2618 43.3591 35.5534C45.7487 35.0024 47.5487 33.4305 48.0289 30.1837ZM39.6727 41.9014C38.5424 46.443 30.8956 43.9878 28.4164 43.3722L30.4247 35.3212C32.9039 35.9399 40.8539 37.1649 39.6727 41.9014ZM40.8039 30.118C39.7727 34.2493 33.4081 32.1503 31.3435 31.6357L33.1643 24.3337C35.2289 24.8482 41.8779 25.8087 40.8039 30.118Z" fill="url(#paint5_linear_14800_609868)"/>
10 - <path d="M48.0289 28.5836C48.6924 24.1481 45.3154 21.7638 40.6977 20.1731L42.1956 14.1648L38.5383 13.2534L37.0799 19.1034C36.1185 18.8638 35.131 18.6377 34.1497 18.4138L35.6185 12.5252L31.9633 11.6138L30.4643 17.62C29.6685 17.4388 28.8872 17.2596 28.1289 17.0711L28.1331 17.0523L23.0893 15.7929L22.1164 19.6992C22.1164 19.6992 24.8299 20.3211 24.7727 20.3596C26.2539 20.7294 26.5216 21.7096 26.4768 22.4867L24.7706 29.3315C24.8727 29.3575 25.0049 29.395 25.1508 29.4534C25.0289 29.4231 24.8987 29.3898 24.7643 29.3575L22.3727 38.9461C22.1914 39.3961 21.732 40.0711 20.6966 39.8148C20.7331 39.8679 18.0383 39.1513 18.0383 39.1513L16.2227 43.3377L20.982 44.5242C21.8674 44.7461 22.7352 44.9784 23.5893 45.1971L22.0758 51.2742L25.7289 52.1856L27.2279 46.1731C28.2258 46.444 29.1945 46.694 30.1424 46.9294L28.6487 52.9138L32.306 53.8252L33.8195 47.7596C40.056 48.9398 44.7456 48.4638 46.7195 42.8231C48.3102 38.2815 46.6404 35.6617 43.3591 33.9534C45.7487 33.4023 47.5487 31.8304 48.0289 28.5836ZM39.6727 40.3013C38.5424 44.8429 30.8956 42.3877 28.4164 41.7721L30.4247 33.7211C32.9039 34.3398 40.8539 35.5648 39.6727 40.3013ZM40.8039 28.5179C39.7727 32.6492 33.4081 30.5502 31.3435 30.0356L33.1643 22.7336C35.2289 23.2481 41.8779 24.2086 40.8039 28.5179Z" fill="white"/>
11 - <path d="M48.0289 28.5836C48.6924 24.1481 45.3154 21.7638 40.6977 20.1731L42.1956 14.1648L38.5383 13.2534L37.0799 19.1034C36.1185 18.8638 35.131 18.6377 34.1497 18.4138L35.6185 12.5252L31.9633 11.6138L30.4643 17.62C29.6685 17.4388 28.8872 17.2596 28.1289 17.0711L28.1331 17.0523L23.0893 15.7929L22.1164 19.6992C22.1164 19.6992 24.8299 20.3211 24.7727 20.3596C26.2539 20.7294 26.5216 21.7096 26.4768 22.4867L24.7706 29.3315C24.8727 29.3575 25.0049 29.395 25.1508 29.4534C25.0289 29.4231 24.8987 29.3898 24.7643 29.3575L22.3727 38.9461C22.1914 39.3961 21.732 40.0711 20.6966 39.8148C20.7331 39.8679 18.0383 39.1513 18.0383 39.1513L16.2227 43.3377L20.982 44.5242C21.8674 44.7461 22.7352 44.9784 23.5893 45.1971L22.0758 51.2742L25.7289 52.1856L27.2279 46.1731C28.2258 46.444 29.1945 46.694 30.1424 46.9294L28.6487 52.9138L32.306 53.8252L33.8195 47.7596C40.056 48.9398 44.7456 48.4638 46.7195 42.8231C48.3102 38.2815 46.6404 35.6617 43.3591 33.9534C45.7487 33.4023 47.5487 31.8304 48.0289 28.5836ZM39.6727 40.3013C38.5424 44.8429 30.8956 42.3877 28.4164 41.7721L30.4247 33.7211C32.9039 34.3398 40.8539 35.5648 39.6727 40.3013ZM40.8039 28.5179C39.7727 32.6492 33.4081 30.5502 31.3435 30.0356L33.1643 22.7336C35.2289 23.2481 41.8779 24.2086 40.8039 28.5179Z" fill="url(#paint6_linear_14800_609868)"/>
12 - <path d="M48.0289 28.5836C48.6924 24.1481 45.3154 21.7638 40.6977 20.1731L42.1956 14.1648L38.5383 13.2534L37.0799 19.1034C36.1185 18.8638 35.131 18.6377 34.1497 18.4138L35.6185 12.5252L31.9633 11.6138L30.4643 17.62C29.6685 17.4388 28.8872 17.2596 28.1289 17.0711L28.1331 17.0523L23.0893 15.7929L22.1164 19.6992C22.1164 19.6992 24.8299 20.3211 24.7727 20.3596C26.2539 20.7294 26.5216 21.7096 26.4768 22.4867L24.7706 29.3315C24.8727 29.3575 25.0049 29.395 25.1508 29.4534C25.0289 29.4231 24.8987 29.3898 24.7643 29.3575L22.3727 38.9461C22.1914 39.3961 21.732 40.0711 20.6966 39.8148C20.7331 39.8679 18.0383 39.1513 18.0383 39.1513L16.2227 43.3377L20.982 44.5242C21.8674 44.7461 22.7352 44.9784 23.5893 45.1971L22.0758 51.2742L25.7289 52.1856L27.2279 46.1731C28.2258 46.444 29.1945 46.694 30.1424 46.9294L28.6487 52.9138L32.306 53.8252L33.8195 47.7596C40.056 48.9398 44.7456 48.4638 46.7195 42.8231C48.3102 38.2815 46.6404 35.6617 43.3591 33.9534C45.7487 33.4023 47.5487 31.8304 48.0289 28.5836ZM39.6727 40.3013C38.5424 44.8429 30.8956 42.3877 28.4164 41.7721L30.4247 33.7211C32.9039 34.3398 40.8539 35.5648 39.6727 40.3013ZM40.8039 28.5179C39.7727 32.6492 33.4081 30.5502 31.3435 30.0356L33.1643 22.7336C35.2289 23.2481 41.8779 24.2086 40.8039 28.5179Z" fill="url(#paint7_linear_14800_609868)"/>
13 - <path d="M35.6185 12.5252L34.1497 18.4138C34.8857 18.5817 35.6251 18.7509 36.3544 18.926L37.0799 19.1034L38.5383 13.2534L42.1956 14.1648L40.6977 20.1731C45.3154 21.7638 48.6924 24.1481 48.0289 28.5836C47.5487 31.8304 45.7487 33.4023 43.3591 33.9534C46.6404 35.6617 48.3102 38.2815 46.7195 42.8231C44.7456 48.4638 40.056 48.9398 33.8195 47.7596L32.306 53.8252L28.6487 52.9138L30.1424 46.9294C29.1945 46.694 28.2258 46.444 27.2279 46.1731L25.7289 52.1856L22.0758 51.2742L23.5893 45.1971C22.7352 44.9784 21.8674 44.7461 20.982 44.5242L16.2227 43.3377L18.0383 39.1513C18.0383 39.1513 20.7331 39.8679 20.6966 39.8148C21.732 40.0711 22.1914 39.3961 22.3727 38.9461L24.7643 29.3575C24.8987 29.3898 25.0289 29.4231 25.1508 29.4534C25.0049 29.395 24.8727 29.3575 24.7706 29.3315L26.4768 22.4867C26.5216 21.7096 26.2539 20.7294 24.7727 20.3596C24.8299 20.3211 22.1184 19.6996 22.1164 19.6992L23.0893 15.7929L28.1331 17.0523L28.1289 17.0711C28.5081 17.1653 28.893 17.2574 29.2826 17.3484L30.4643 17.62L31.9633 11.6138L35.6185 12.5252ZM30.8552 18.256L30.3458 18.1401C29.5502 17.9589 28.7643 17.7785 28.0003 17.5885L27.4953 17.4632L27.4995 17.4437L23.4776 16.4396L22.7646 19.3021C23.0032 19.3576 23.2971 19.4264 23.5898 19.4963C23.9261 19.5766 24.264 19.6589 24.5154 19.7239C24.6397 19.7561 24.7494 19.7857 24.8286 19.8096C24.8651 19.8206 24.9101 19.8347 24.9497 19.8505C24.954 19.8522 24.9643 19.8564 24.9784 19.8627C25.7828 20.0791 26.3243 20.4754 26.6474 20.9846C26.9735 21.4985 27.0357 22.061 27.0094 22.5174L27.0065 22.5672L26.9943 22.6156L25.288 29.4604L25.1943 29.4369L25.1862 29.4627L25.2818 29.4867L22.8901 39.0752L22.8812 39.1109L22.8674 39.1453C22.7572 39.419 22.5476 39.8027 22.1674 40.0776C21.7796 40.358 21.268 40.4848 20.6432 40.3489C20.6232 40.3474 20.6088 40.3457 20.6034 40.345C20.5651 40.34 20.5217 40.3315 20.4849 40.3239C20.4057 40.3076 20.2964 40.2821 20.1716 40.252C19.9199 40.1913 19.583 40.1059 19.2479 40.0195C18.9218 39.9354 18.595 39.8496 18.3451 39.7838L16.9622 42.9724L21.1109 44.0067H21.1117C21.9966 44.2285 22.8772 44.4642 23.7216 44.6804L24.2349 44.8119L22.7219 50.8856L25.3404 51.539L26.8422 45.5159L27.3674 45.6586C28.3612 45.9283 29.3264 46.1771 30.2711 46.4117L30.7893 46.5406L29.2953 52.5252L31.9174 53.1786L33.424 47.1419L33.9187 47.2356C37.0189 47.8223 39.6425 47.9761 41.7112 47.3396C43.7316 46.7178 45.2792 45.3243 46.2161 42.6471C46.9818 40.4608 46.9366 38.8163 46.3776 37.5395C45.8155 36.2558 44.693 35.2493 43.1128 34.4265L41.8302 33.7586L43.2393 33.4336C44.3532 33.1767 45.2981 32.6901 46.0198 31.9159C46.741 31.142 47.2738 30.0439 47.5013 28.5054L47.5016 28.5047C47.8072 26.4614 47.1908 24.9228 45.9651 23.6872C44.7129 22.4249 42.8067 21.4636 40.524 20.6773L40.062 20.5182L41.549 14.5531L38.9266 13.8997L37.4685 19.7497L36.951 19.6208C35.9955 19.3827 35.0128 19.1579 34.031 18.9338L33.5005 18.8127L34.9719 12.9135L32.3516 12.2601L30.8552 18.256ZM30.5539 33.2036C31.7395 33.4995 34.4332 33.9792 36.6417 34.9815C37.7505 35.4847 38.8004 36.1452 39.4948 37.0336C40.2086 37.9469 40.5272 39.0789 40.1901 40.4304C39.8638 41.7411 39.0508 42.5639 37.999 43.0226C36.9747 43.4693 35.7396 43.5667 34.5227 43.5034C32.0931 43.3768 29.4876 42.5878 28.2878 42.2898L27.7698 42.1612L30.0365 33.0744L30.5539 33.2036ZM28.4164 41.7721C30.8956 42.3877 38.5424 44.8429 39.6727 40.3013C40.8539 35.5648 32.9039 34.3398 30.4247 33.7211L28.4164 41.7721ZM33.2932 22.2161C34.2662 22.4586 36.5394 22.8473 38.3888 23.7203C39.3203 24.16 40.2074 24.7487 40.7872 25.5578C41.3838 26.3903 41.6272 27.4193 41.3214 28.6468C41.0242 29.8374 40.3257 30.6069 39.4141 31.05C38.5281 31.4805 37.4712 31.5899 36.4417 31.552C34.3912 31.4767 32.2032 30.7995 31.2146 30.5531L30.6969 30.4242L32.7758 22.0872L33.2932 22.2161ZM31.3435 30.0356C33.4081 30.5502 39.7727 32.6492 40.8039 28.5179C41.8779 24.2086 35.2289 23.2481 33.1643 22.7336L31.3435 30.0356Z" fill="url(#paint8_linear_14800_609868)"/>
14 - </g>
15 - <path d="M96.2235 71.9527C91.7714 89.81 73.6849 100.678 55.8255 96.2245C37.9735 91.7725 27.1058 73.685 31.5599 55.8287C36.0099 37.9693 54.0964 27.1006 71.9505 31.5527C89.8089 36.0048 100.676 54.0943 96.2235 71.9527Z" fill="#F7931A"/>
16 - <path d="M96.2235 71.9527C91.7714 89.81 73.6849 100.678 55.8255 96.2245C37.9735 91.7725 27.1058 73.685 31.5599 55.8287C36.0099 37.9693 54.0964 27.1006 71.9505 31.5527C89.8089 36.0048 100.676 54.0943 96.2235 71.9527Z" fill="url(#paint9_linear_14800_609868)"/>
17 - <path d="M96.2235 71.9527C91.7714 89.81 73.6849 100.678 55.8255 96.2245C37.9735 91.7725 27.1058 73.685 31.5599 55.8287C36.0099 37.9693 54.0964 27.1006 71.9505 31.5527C89.8089 36.0048 100.676 54.0943 96.2235 71.9527Z" fill="url(#paint10_linear_14800_609868)"/>
18 - <path d="M96.2235 71.9527C91.7714 89.81 73.6849 100.678 55.8255 96.2245C37.9735 91.7725 27.1058 73.685 31.5599 55.8287C36.0099 37.9693 54.0964 27.1006 71.9505 31.5527C89.8089 36.0048 100.676 54.0943 96.2235 71.9527Z" fill="url(#paint11_linear_14800_609868)"/>
19 - <path d="M31.5599 55.8287C36.01 37.9694 54.0964 27.1006 71.9506 31.5527C89.8089 36.0047 100.676 54.0944 96.2235 71.9526L96.1167 72.3701C91.5253 89.8403 73.827 100.475 56.244 96.3261L55.8256 96.2245C37.9735 91.7724 27.1058 73.6849 31.5599 55.8287ZM71.6279 32.8464C54.4885 28.5726 37.1257 39.0063 32.8537 56.1511V56.1516C28.5778 73.2933 39.0106 90.6568 56.148 94.9308C73.2928 99.2057 90.6558 88.7729 94.9297 71.6303C99.2037 54.4862 88.7715 37.1203 71.6279 32.8464Z" fill="url(#paint12_linear_14800_609868)"/>
20 - <path d="M31.5599 55.8287C36.01 37.9694 54.0964 27.1006 71.9506 31.5527C89.8089 36.0047 100.676 54.0944 96.2235 71.9526L96.1167 72.3701C91.5253 89.8403 73.827 100.475 56.244 96.3261L55.8256 96.2245C37.9735 91.7724 27.1058 73.6849 31.5599 55.8287ZM71.6279 32.8464C54.4885 28.5726 37.1257 39.0063 32.8537 56.1511V56.1516C28.5778 73.2933 39.0106 90.6568 56.148 94.9308C73.2928 99.2057 90.6558 88.7729 94.9297 71.6303C99.2037 54.4862 88.7715 37.1203 71.6279 32.8464Z" fill="url(#paint13_linear_14800_609868)"/>
21 - <path d="M31.5599 55.8287C36.01 37.9694 54.0964 27.1006 71.9506 31.5527C89.8089 36.0047 100.676 54.0944 96.2235 71.9526L96.1167 72.3701C91.5253 89.8403 73.827 100.475 56.244 96.3261L55.8256 96.2245C37.9735 91.7724 27.1058 73.6849 31.5599 55.8287ZM71.6279 32.8464C54.4885 28.5726 37.1257 39.0063 32.8537 56.1511V56.1516C28.5778 73.2933 39.0106 90.6568 56.148 94.9308C73.2928 99.2057 90.6558 88.7729 94.9297 71.6303C99.2037 54.4862 88.7715 37.1203 71.6279 32.8464Z" fill="url(#paint14_linear_14800_609868)"/>
22 - <path d="M46.5206 67.6513L71.4546 46.1656C72.5411 45.4698 73.5767 46.1656 72.9135 47.3592L64.9559 63.0094H79.147C79.147 63.0094 81.4017 63.0094 79.147 64.8662L54.6109 86.4844C52.8868 87.9434 51.6931 87.1476 52.8868 84.8929L60.5792 69.6408H46.5206C46.5206 69.6408 44.266 69.6408 46.5206 67.6513Z" fill="url(#paint15_linear_14800_609868)"/>
23 - <path d="M46.5206 64.9843L71.4546 43.4986C72.5411 42.8028 73.5767 43.4986 72.9135 44.6922L64.9559 60.3424H79.147C79.147 60.3424 81.4017 60.3424 79.147 62.1992L54.6109 83.8175C52.8868 85.2764 51.6931 84.4806 52.8868 82.2259L60.5792 66.9738H46.5206C46.5206 66.9738 44.266 66.9738 46.5206 64.9843Z" fill="url(#paint16_linear_14800_609868)"/>
24 - <path d="M71.4547 43.4985C72.5412 42.8028 73.5767 43.4987 72.9136 44.6922L64.9558 60.3425H79.1469C79.1469 60.3425 81.4016 60.3425 79.1469 62.1993L54.611 83.8175L54.5305 83.8842C52.8501 85.2511 51.7118 84.4453 52.8868 82.2258L60.5792 66.9738H46.5206L46.4282 66.9699C46.0347 66.9431 44.6002 66.7328 46.4183 65.0761L46.5206 64.9844L71.4547 43.4985ZM72.5183 43.812C72.4487 43.7593 72.185 43.6755 71.7693 43.931L46.8688 65.3883C46.3257 65.8682 46.1264 66.1691 46.0683 66.323C46.065 66.3316 46.0628 66.3394 46.0607 66.3462C46.1043 66.369 46.1825 66.3974 46.2962 66.4175C46.3611 66.429 46.4211 66.4349 46.4644 66.4378C46.4856 66.4393 46.502 66.4399 46.512 66.4402C46.517 66.4403 46.5204 66.4404 46.5219 66.4404H61.4454L53.3631 82.4662L53.3605 82.4709L53.3581 82.4756C53.0793 83.0022 52.963 83.4021 52.9417 83.6727C52.9312 83.8059 52.945 83.8923 52.961 83.9422C52.9759 83.9887 52.9913 84.0006 52.9925 84.0016C52.9944 84.0032 53.0085 84.0146 53.0527 84.0196C53.1015 84.0251 53.1828 84.0218 53.3006 83.9883C53.5397 83.9204 53.8712 83.7446 54.2665 83.4102L78.7943 61.799L78.8011 61.793L78.8079 61.7876C79.3195 61.3662 79.5217 61.0955 79.5902 60.9537C79.5427 60.9347 79.4718 60.9133 79.3774 60.8977C79.311 60.8868 79.25 60.881 79.2058 60.8782C79.184 60.8768 79.167 60.8761 79.1566 60.8758H64.0863L72.4381 44.4506L72.4425 44.4417L72.4472 44.4331C72.5755 44.2022 72.5953 44.0424 72.587 43.954C72.5796 43.8743 72.5499 43.836 72.5183 43.812Z" fill="white"/>
25 - </g>
26 - <defs>
27 - <linearGradient id="paint0_linear_14800_609868" x1="33.3333" y1="0" x2="33.3333" y2="66.6673" gradientUnits="userSpaceOnUse">
28 - <stop stop-color="#F7BC1A"/>
29 - <stop offset="1" stop-color="#FF6A00"/>
30 - </linearGradient>
31 - <linearGradient id="paint1_linear_14800_609868" x1="33.3333" y1="0" x2="33.3333" y2="66.6673" gradientUnits="userSpaceOnUse">
32 - <stop offset="0.725084" stop-color="#C94701" stop-opacity="0"/>
33 - <stop offset="1" stop-color="#C94701" stop-opacity="0.3"/>
34 - </linearGradient>
35 - <linearGradient id="paint2_linear_14800_609868" x1="33.3333" y1="9.32637e-05" x2="33.3333" y2="66.6674" gradientUnits="userSpaceOnUse">
36 - <stop stop-color="#FFE091"/>
37 - <stop offset="1" stop-color="#FF9735"/>
38 - </linearGradient>
39 - <linearGradient id="paint3_linear_14800_609868" x1="33.3333" y1="9.32637e-05" x2="33.3333" y2="66.6674" gradientUnits="userSpaceOnUse">
40 - <stop offset="0.85" stop-color="#FFA54D" stop-opacity="0"/>
41 - <stop offset="1" stop-color="#FFA54D"/>
42 - </linearGradient>
43 - <linearGradient id="paint4_linear_14800_609868" x1="33.3333" y1="9.32637e-05" x2="33.3333" y2="66.6674" gradientUnits="userSpaceOnUse">
44 - <stop stop-color="#FFF3DA"/>
45 - <stop offset="0.15" stop-color="#FFF3DA" stop-opacity="0"/>
46 - </linearGradient>
47 - <linearGradient id="paint5_linear_14800_609868" x1="32.1674" y1="13.2139" x2="32.1674" y2="55.4253" gradientUnits="userSpaceOnUse">
48 - <stop stop-color="#F89A02"/>
49 - <stop offset="1" stop-color="#F56600"/>
50 - </linearGradient>
51 - <linearGradient id="paint6_linear_14800_609868" x1="32.1675" y1="11.6138" x2="32.1675" y2="53.8252" gradientUnits="userSpaceOnUse">
52 - <stop stop-color="white"/>
53 - <stop offset="1" stop-color="#FFF1CF"/>
54 - </linearGradient>
55 - <linearGradient id="paint7_linear_14800_609868" x1="32.1675" y1="11.6138" x2="32.1675" y2="53.8252" gradientUnits="userSpaceOnUse">
56 - <stop stop-color="white"/>
57 - <stop offset="1" stop-color="#FEEABD"/>
58 - </linearGradient>
59 - <linearGradient id="paint8_linear_14800_609868" x1="32.1675" y1="11.6138" x2="32.1675" y2="53.8252" gradientUnits="userSpaceOnUse">
60 - <stop stop-color="white"/>
61 - <stop offset="1" stop-color="white"/>
62 - </linearGradient>
63 - <linearGradient id="paint9_linear_14800_609868" x1="63.8913" y1="30.5552" x2="63.8913" y2="97.2225" gradientUnits="userSpaceOnUse">
64 - <stop stop-color="#F7BC1A"/>
65 - <stop offset="1" stop-color="#FF7700"/>
66 - </linearGradient>
67 - <linearGradient id="paint10_linear_14800_609868" x1="63.8913" y1="30.5552" x2="63.8913" y2="97.2225" gradientUnits="userSpaceOnUse">
68 - <stop stop-color="#F7BC1A"/>
69 - <stop offset="1" stop-color="#FF6A00"/>
70 - </linearGradient>
71 - <linearGradient id="paint11_linear_14800_609868" x1="63.8913" y1="30.5552" x2="63.8913" y2="97.2225" gradientUnits="userSpaceOnUse">
72 - <stop offset="0.725084" stop-color="#C94701" stop-opacity="0"/>
73 - <stop offset="1" stop-color="#C94701" stop-opacity="0.3"/>
74 - </linearGradient>
75 - <linearGradient id="paint12_linear_14800_609868" x1="63.8913" y1="30.5553" x2="63.8913" y2="97.2226" gradientUnits="userSpaceOnUse">
76 - <stop stop-color="#FFE091"/>
77 - <stop offset="1" stop-color="#FF9735"/>
78 - </linearGradient>
79 - <linearGradient id="paint13_linear_14800_609868" x1="63.8913" y1="30.5553" x2="63.8913" y2="97.2226" gradientUnits="userSpaceOnUse">
80 - <stop offset="0.85" stop-color="#FFA54D" stop-opacity="0"/>
81 - <stop offset="1" stop-color="#FFA54D"/>
82 - </linearGradient>
83 - <linearGradient id="paint14_linear_14800_609868" x1="63.8913" y1="30.5553" x2="63.8913" y2="97.2226" gradientUnits="userSpaceOnUse">
84 - <stop stop-color="#FFF3DA"/>
85 - <stop offset="0.15" stop-color="#FFF3DA" stop-opacity="0"/>
86 - </linearGradient>
87 - <linearGradient id="paint15_linear_14800_609868" x1="62.8338" y1="45.8887" x2="62.8338" y2="87.222" gradientUnits="userSpaceOnUse">
88 - <stop stop-color="#F89A02"/>
89 - <stop offset="1" stop-color="#F56600"/>
90 - </linearGradient>
91 - <linearGradient id="paint16_linear_14800_609868" x1="62.8338" y1="43.2217" x2="62.8338" y2="84.555" gradientUnits="userSpaceOnUse">
92 - <stop stop-color="white"/>
93 - <stop offset="1" stop-color="#FEEABD"/>
94 - </linearGradient>
95 - <clipPath id="clip0_14800_609868">
96 - <rect width="100" height="100" fill="white"/>
97 - </clipPath>
98 - </defs>
99 -</svg>
assets/litecoin_electrum_server_list.yml
+7
@@ -2,20 +2,27 @@
2 uri: ltc-electrum.cakewallet.com:50002
3 useSSL: true
4 isDefault: true
5 + isOfficial: true
6 isEnabledForAutoSwitching: true
7 + label: "Cake Wallet"
8 -
9 uri: litecoin.stackwallet.com:20063
10 useSSL: true
11 isEnabledForAutoSwitching: true
12 + label: "Stack Wallet"
13 -
14 uri: electrum-ltc.bysh.me:50002
15 useSSL: true
16 + label: "Bysh"
17 -
18 uri: lightweight.fiatfaucet.com:50002
19 useSSL: true
20 + label: "Fiat Faucet"
21 -
22 uri: electrum.ltc.xurious.com:50002
23 useSSL: true
24 + label: "Xurious"
25 -
26 uri: backup.electrum-ltc.org:443
27 useSSL: true
28 + label: "Electrum-LTC"
assets/nano_node_list.yml
+10 -7
@@ -1,34 +1,37 @@
1 -
2 - uri: nano.nownodes.io
2 + uri: rpc.nano.to
3 + isDefault: true
4 useSSL: true
5 isEnabledForAutoSwitching: true
6 + label: "Nano.to"
7 -
6 - uri: rpc.nano.to
7 - is_default: true
8 + uri: nano.nownodes.io
9 useSSL: true
10 isEnabledForAutoSwitching: true
11 + label: "NOWNodes"
12 -
13 uri: node.nautilus.io
14 path: /api
15 useSSL: true
16 isEnabledForAutoSwitching: true
17 + label: "Nautilus"
18 -
19 uri: app.natrium.io
20 path: /api
21 useSSL: true
22 + label: "Natrium"
23 -
24 uri: rainstorm.city
25 path: /api
26 useSSL: true
27 + label: "Rainstorm City"
28 -
29 uri: node.somenano.com
30 path: /proxy
31 useSSL: true
32 + label: "SomeNano"
33 -
34 uri: nanoslo.0x.no
35 path: /proxy
36 useSSL: true
31 --
32 - uri: www.bitrequest.app
33 - port: 8020
34 - useSSL: true
\ No newline at end of file
37 + label: "0x.no"
\ No newline at end of file
assets/node_list.yml
+10 -8
@@ -1,34 +1,36 @@
1 -
2 + label: "Cake Wallet"
3 uri: xmr-node.cakewallet.com:18081
3 - is_default: true
4 + isDefault: true
5 + isOfficial: true
6 trusted: true
7 useSSL: true
8 isEnabledForAutoSwitching: true
9 -
10 + label: "Cake Wallet (Onion)"
11 uri: cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081
9 - is_default: false
12 -
13 + label: "Seth For Privacy"
14 uri: node.sethforprivacy.com:443
15 useSSL: true
13 - is_default: false
16 isEnabledForAutoSwitching: true
17 -
18 + label: "MoneroDevs"
19 uri: node.monerodevs.org:18089
20 useSSL: true
18 - is_default: false
21 -
22 + label: "MoneroDevs #2"
23 uri: node2.monerodevs.org:18089
24 useSSL: true
22 - is_default: false
25 -
26 + label: "MoneroDevs #3"
27 uri: node3.monerodevs.org:18089
28 useSSL: true
26 - is_default: false
29 -
30 + label: "Feather Wallet"
31 uri: selsta1.featherwallet.net:18081
32 useSSL: true
30 - is_default: false
33 -
34 + label: "StormyCloud"
35 uri: xmr.stormycloud.org:18089
36 useSSL: true
34 - is_default: false
assets/polygon_node_list.yml
+5 -5
@@ -1,14 +1,14 @@
1 --
2 - uri: polygon-rpc.com
1 -
2 uri: polygon-bor-rpc.publicnode.com
3 useSSL: true
4 isDefault: true
5 isEnabledForAutoSwitching: true
6 + label: "polygon-bor-rpc.publicnode.com"
7 -
9 - uri: polygon.llamarpc.com
10 - useSSL: true
8 + uri: polygon-rpc.com
9 + label: "Ankr"
10 -
11 uri: matic.nownodes.io
12 useSSL: true
14 - isEnabledForAutoSwitching: true
\ No newline at end of file
13 + isEnabledForAutoSwitching: true
14 + label: "NOWNodes"
\ No newline at end of file
assets/solana_node_list.yml
+9 -5
@@ -1,16 +1,20 @@
1 +-
2 + uri: solana-mainnet.core.chainstack.com
3 + useSSL: true
4 + isDefault: true
5 + isEnabledForAutoSwitching: true
6 + label: "Chainstack"
7 -
8 uri: rpc.ankr.com
9 useSSL: true
10 + label: "Ankr"
11 -
12 uri: api.mainnet-beta.solana.com:443
13 useSSL: true
14 isEnabledForAutoSwitching: true
15 + label: "Solana Beta"
16 -
17 uri: solana-rpc.publicnode.com:443
18 useSSL: true
19 isEnabledForAutoSwitching: true
12 --
13 - uri: solana-mainnet.core.chainstack.com
14 - useSSL: true
15 - is_default: true
16 - isEnabledForAutoSwitching: true
\ No newline at end of file
20 + label: "PublicNode"
\ No newline at end of file
assets/tron_node_list.yml
+8 -6
@@ -1,13 +1,15 @@
1 --
2 - uri: tron-rpc.publicnode.com:443
3 - is_default: false
4 - useSSL: true
1 -
2 uri: api.trongrid.io
7 - is_default: true
3 + isDefault: true
4 useSSL: true
5 isEnabledForAutoSwitching: true
6 + label: "TronGrid"
7 +-
8 + uri: tron-rpc.publicnode.com:443
9 + useSSL: true
10 + label: "PublicNode"
11 -
12 uri: trx.nownodes.io
13 useSSL: true
13 - isEnabledForAutoSwitching: true
\ No newline at end of file
14 + isEnabledForAutoSwitching: true
15 + label: "NOWNodes"
\ No newline at end of file
assets/wownero_node_list.yml
+1 -3
@@ -1,14 +1,12 @@
1 -
2 uri: node3.monerodevs.org:34568
3 - is_default: true
3 + isDefault: true
4 useSSL: false
5 isEnabledForAutoSwitching: true
6 -
7 uri: node2.monerodevs.org:34568
8 - is_default: false
8 useSSL: false
9 isEnabledForAutoSwitching: true
10 -
11 uri: node.monerodevs.org:34568
13 - is_default: false
12 useSSL: false
assets/zano_node_list.yml
+5 -2
@@ -1,9 +1,12 @@
1 -
2 uri: 37.27.100.59:10500
3 - is_default: true
3 + isDefault: true
4 useSSL: false
5 isEnabledForAutoSwitching: true
6 + label: "Zano"
7 -
8 uri: zano.cakewallet.com:11211
9 useSSL: false
9 - isEnabledForAutoSwitching: true
\ No newline at end of file
10 + isOfficial: true
11 + isEnabledForAutoSwitching: true
12 + label: "Cake Wallet"
assets/zcash_node_list.yml
+14 -6
@@ -1,12 +1,20 @@
1 -- uri: zec.rocks:443
2 - is_default: false
1 +-
2 + uri: zec-node.cakewallet.com:443
3 + isDefault: true
4 + isOfficial: true
5 useSSL: true
6 isEnabledForAutoSwitching: true
5 -- uri: zec-node.cakewallet.com:443
6 - is_default: true
7 + label: "Cake Wallet"
8 +-
9 + uri: zec.rocks:443
10 useSSL: true
11 isEnabledForAutoSwitching: true
9 -- uri: 2c4whzg26j6hgjh22rxynj3oig4gm22ga7x74weclujywxye23v3u5id.onion:9067
12 + label: "Zec.rocks"
13 +-
14 + uri: 2c4whzg26j6hgjh22rxynj3oig4gm22ga7x74weclujywxye23v3u5id.onion:9067
15 useSSL: false
11 -- uri: bvp2l442g5ogma7rywzahm7eqyhpp3g26n3gvvxeioqn5csio2ir6myd.onion:9067
16 + label: "Cake Wallet (Tor)"
17 +-
18 + uri: bvp2l442g5ogma7rywzahm7eqyhpp3g26n3gvvxeioqn5csio2ir6myd.onion:9067
19 useSSL: false
20 + label: "Cake Wallet (Tor #2)"
\ No newline at end of file
cw_bitcoin/lib/electrum_wallet.dart
+3 -2
@@ -790,9 +790,10 @@ abstract class ElectrumWalletBase
790
791 if (server.toLowerCase().contains('electrs')) {
792 node!.isElectrs = true;
793 - if (node!.isInBox) {
793 + // TODO figure out why condition was needed
794 + // if (node!.isInBox) {
795 node!.save();
795 - }
796 + // }
797 return node!.isElectrs!;
798 }
799 }
cw_core/lib/db/sqlite.dart
+27 -1
@@ -41,7 +41,7 @@ Future<void> initDb({String? pathOverride}) async {
41 }
42 }
43 await db?.close();
44 - db = await openDatabase(dbFile.path, version: 7,
44 + db = await openDatabase(dbFile.path, version: 8,
45 onUpgrade: (Database db, int oldVersion, int newVersion) async {
46 printV("migrating: $oldVersion, $newVersion");
47 if (oldVersion <= 1) {
@@ -104,6 +104,9 @@ CREATE TABLE IF NOT EXISTS BalanceCardStyleSettings (
104 definition: 'TEXT',
105 );
106 }
107 + if(oldVersion <= 7) {
108 + await _createNodeTable(db);
109 + }
110 },
111 onCreate: (Database db, int version) async {
112 await db.execute(
@@ -202,6 +205,7 @@ CREATE TABLE BalanceCardStyleSettings (
205 );
206 ''');
207 await _createBridgeTransferTable(db);
208 + await _createNodeTable(db);
209 await _createTradeTable(db);
210 }
211 );
@@ -330,4 +334,26 @@ CREATE TABLE IF NOT EXISTS BridgeTransfer (
334 CREATE INDEX IF NOT EXISTS idx_bridgetransfer_wallet_id
335 ON BridgeTransfer(wallet_id);
336 ''');
337 +}
338 +
339 +Future<void> _createNodeTable(Database db) async {
340 + db.execute("""
341 +CREATE TABLE Node (
342 +NodeId INTEGER PRIMARY KEY,
343 +uri TEXT NOT NULL,
344 +path TEXT,
345 +login TEXT,
346 +label TEXT,
347 +password TEXT,
348 +isPow INTEGER NOT NULL,
349 +useSSL INTEGER,
350 +typeRaw INTEGER NOT NULL,
351 +trusted INTEGER NOT NULL,
352 +socksProxyAddress TEXT,
353 +isEnabledForAutoSwitching BOOLEAN DEFAULT FALSE,
354 +isOfficial BOOLEAN DEFAULT FALSE,
355 +isBuiltin BOOLEAN DEFAULT FALSE,
356 +isDefault BOOLEAN DEFAULT FALSE
357 +);
358 + """);
359 }
\ No newline at end of file
cw_core/lib/node.dart
+154 -50
@@ -1,33 +1,62 @@
1 +import 'dart:convert';
2 import 'dart:io';
2 -import 'package:cw_core/keyable.dart';
3 +import 'dart:math' as math;
4 +
5 +import 'package:blockchain_utils/hex/hex.dart';
6 +import 'package:cw_core/node_list.dart';
7 +import 'package:cw_core/utils/print_verbose.dart';
8 import 'package:cw_core/utils/proxy_socket/abstract.dart';
9 import 'package:cw_core/utils/proxy_wrapper.dart';
5 -import 'package:cw_core/utils/print_verbose.dart';
6 -import 'dart:convert';
7 -import 'package:hive/hive.dart';
8 -import 'package:cw_core/hive_type_ids.dart';
10 import 'package:cw_core/wallet_type.dart';
10 -import 'dart:math' as math;
11 -import 'package:convert/convert.dart';
12 -
11 import 'package:crypto/crypto.dart';
12 +import 'package:sqflite/sqflite.dart';
13
15 -part 'node.g.dart';
14 +import 'db/sqlite.dart';
15
16 Uri createUriFromElectrumAddress(String address, String path) =>
17 Uri.tryParse('tcp://$address$path')!;
18
20 -@HiveType(typeId: Node.typeId)
21 -class Node extends HiveObject with Keyable {
19 +Future<void> validateBuiltinNodes() async {
20 + // ensures nodes stored as builtin in the db correspond to the nodes in the .yml files
21 +
22 + final builtinFromDb = await Node.getAllBuiltin();
23 + final builtinFromList = await loadAllDefaultNodes();
24 +
25 + for (final listNode in builtinFromList) {
26 + // preserve proxy settings from user
27 + try {
28 + final matchedDbNode = builtinFromDb.firstWhere(
29 + (dbNode) => dbNode.uri == listNode.uri
30 + );
31 + listNode.socksProxyAddress = matchedDbNode.socksProxyAddress;
32 + } catch(e) {}
33 + }
34 +
35 + final dbSet = builtinFromDb.toSet();
36 + final listSet = builtinFromList.toSet();
37 +
38 + final nodesToDelete = dbSet.difference(listSet);
39 + final nodesToAdd = listSet.difference(dbSet);
40 +
41 + for (final node in nodesToDelete) await node.delete();
42 + for (final node in nodesToAdd) await node.save();
43 +}
44 +
45 +class Node {
46 Node({
47 + this.id = 0,
48 this.label,
49 this.login,
50 this.password,
51 this.useSSL,
52 + this.isPow = false,
53 this.trusted = false,
54 this.socksProxyAddress,
55 this.path = '',
56 this.isEnabledForAutoSwitching = false,
57 + this.isOfficial = false,
58 + this.isBuiltin = false,
59 + this.isDefault = false,
60 String? uri,
61 WalletType? type,
62 }) {
@@ -50,62 +79,144 @@ class Node extends HiveObject with Keyable {
79 trusted: $trusted,
80 socksProxyAddress: $socksProxyAddress,
81 isEnabledForAutoSwitching: $isEnabledForAutoSwitching,
82 + isOfficial: $isOfficial,
83 + isBuiltin: $isBuiltin,
84 + isDefault: $isDefault
85 })""";
86 }
87
88 Node.fromMap(Map<String, Object?> map)
57 - : uriRaw = map['uri'] as String? ?? '',
89 + : id = (map[selfIdColumn] ?? 0) as int,
90 + uriRaw = map['uri'] as String? ?? '',
91 path = map['path'] as String? ?? '',
92 login = map['login'] as String?,
93 label = map['label'] as String?,
94 password = map['password'] as String?,
62 - useSSL = map['useSSL'] as bool?,
63 - trusted = map['trusted'] as bool? ?? false,
64 - socksProxyAddress = map['socksProxyPort'] as String?,
65 - isEnabledForAutoSwitching = map['isEnabledForAutoSwitching'] as bool? ?? false;
95 + isPow = (map["isPow"] != null && map['isPow'] != 0) as bool? ?? false,
96 + useSSL = (map['useSSL'] != 0) as bool?,
97 + typeRaw = (map["typeRaw"] ?? 0) as int,
98 + trusted = (map['trusted'] != 0) as bool? ?? false,
99 + socksProxyAddress = map['socksProxyAddress'] as String?,
100 + isEnabledForAutoSwitching = (map['isEnabledForAutoSwitching'] != 0) as bool? ?? false,
101 + isOfficial = (map['isOfficial'] != 0) as bool? ?? false,
102 + isBuiltin = (map['isBuiltin'] != 0) as bool? ?? false,
103 + isDefault = (map['isDefault'] != 0) as bool? ?? false;
104 +
105 + Map<String, dynamic> toMap() {
106 + return {
107 + selfIdColumn: id,
108 + 'uri': uriRaw,
109 + 'path': path,
110 + 'login': login,
111 + "label": label,
112 + 'password': password,
113 + "isPow": isPow,
114 + 'useSSL': useSSL,
115 + "typeRaw": typeRaw,
116 + 'trusted': trusted,
117 + 'socksProxyAddress': socksProxyAddress,
118 + 'isEnabledForAutoSwitching': isEnabledForAutoSwitching,
119 + "isOfficial": isOfficial,
120 + "isBuiltin": isBuiltin,
121 + "isDefault": isDefault
122 + };
123 + }
124
67 - static const typeId = NODE_TYPE_ID;
68 - static const boxName = 'Nodes';
125 + Future<int> delete() async {
126 + return await db!.delete(tableName, where: '${selfIdColumn} = ?', whereArgs: [id]);
127 + }
128
70 - @HiveField(0, defaultValue: '')
71 - late String uriRaw;
129 + static Future<int> deleteAll() async {
130 + return await db!.delete(tableName, where: "isPow = ?", whereArgs: [false]);
131 + }
132
73 - @HiveField(1)
74 - String? login;
133 + static Future<int> deleteAllPow() async {
134 + return await db!.delete(tableName, where: "isPow = ?", whereArgs: [true]);
135 + }
136
76 - @HiveField(2)
77 - String? password;
137 + Future<int> save() async {
138
79 - @HiveField(3, defaultValue: 0)
80 - late int typeRaw;
139 + final json = toMap();
140 + if (json[selfIdColumn] == 0) {
141 + json[selfIdColumn] = null;
142 + }
143 + id = await db!.insert(tableName, json, conflictAlgorithm: ConflictAlgorithm.replace);
144 + return id;
145 + }
146
82 - @HiveField(4)
83 - bool? useSSL;
147
85 - @HiveField(5, defaultValue: false)
86 - bool trusted;
148 + static Future<List<Node>> selectList(String where, List<dynamic> whereArgs, {String? orderBy}) async {
149 + if(orderBy == null) {
150 + orderBy = selfIdColumn;
151 + }
152 + final list = await db!.query(
153 + tableName,
154 + where: where.isNotEmpty ? where : "1 = 1",
155 + whereArgs: whereArgs.isNotEmpty ? whereArgs : null,
156 + orderBy: orderBy,
157 + );
158 + printV("selectList: $list");
159 + return List.generate(list.length, (index) => Node.fromMap(list[index]));
160 + }
161
88 - @HiveField(6)
89 - String? socksProxyAddress;
162
91 - @HiveField(7, defaultValue: '')
92 - String? path;
163 + static Future<List<Node>> getAll() async {
164 + return selectList("isPow = ?", [false]);
165 + }
166
94 - @HiveField(8)
95 - bool? isElectrs;
167 + static Future<List<Node>> getAllBuiltin() async {
168 + return selectList("isPow = ? AND isBuiltin = ?", [false, true]);
169 + }
170
97 - @HiveField(9)
98 - bool? supportsSilentPayments;
171 + static Future<List<Node>> getAllPowBuiltin() async {
172 + return selectList("isPow = ? AND isBuiltin = ?", [true, true]);
173 + }
174
100 - @HiveField(10)
101 - bool? supportsMweb;
175 + static Future<List<Node>> getAllForWalletType(WalletType type) async {
176 + return selectList("typeRaw = ? AND isPow = ?", [serializeToInt(type), false]);
177 + }
178 +
179 + static Future<Node?> getDefaultForWalletType(WalletType type) async {
180 + return (await selectList("typeRaw = ? AND isPow = ? AND isDefault = ?", [serializeToInt(type), false, true])).firstOrNull;
181 + }
182
103 - @HiveField(11, defaultValue: false)
183 + static Future<Node?> getDefaultPowForWalletType(WalletType type) async {
184 + return (await selectList("typeRaw = ? AND isPow = ? AND isDefault = ?", [serializeToInt(type), true, true])).firstOrNull;
185 + }
186 +
187 + static Future<List<Node>> getAllForWalletTypePow(WalletType type) async {
188 + return selectList("typeRaw = ? AND isPow = ?", [serializeToInt(type), true]);
189 + }
190 +
191 + static Future<List<Node>> getAllPow() async {
192 + return selectList("isPow = ?", [true]);
193 + }
194 +
195 +
196 + int id;
197 + late String uriRaw;
198 + String? login;
199 + String? password;
200 + late int typeRaw;
201 + bool? useSSL;
202 + bool trusted;
203 + bool isPow;
204 + String? socksProxyAddress;
205 + String? path;
206 + bool? isElectrs;
207 + bool? supportsSilentPayments;
208 + bool? supportsMweb;
209 bool isEnabledForAutoSwitching;
210 + bool isOfficial;
211 + bool isBuiltin;
212 + bool isDefault;
213
106 - @HiveField(12, defaultValue: '')
214 String? label;
215
216 + static String get tableName => "Node";
217 + static String get selfIdColumn => "${tableName}Id";
218 +
219 +
220 bool get isSSL => useSSL ?? false;
221
222 bool get useSocksProxy => socksProxyAddress == null ? false : socksProxyAddress!.isNotEmpty;
@@ -167,18 +278,11 @@ class Node extends HiveObject with Keyable {
278 socksProxyAddress.hashCode ^
279 path.hashCode;
280
170 - @override
171 - dynamic get keyIndex {
172 - _keyIndex ??= key;
173 - return _keyIndex;
174 - }
281
282 WalletType get type => deserializeFromInt(typeRaw);
283
284 set type(WalletType type) => typeRaw = serializeToInt(type);
285
180 - dynamic _keyIndex;
181 -
286 Future<bool> requestNode() async {
287 try {
288 switch (type) {
@@ -228,7 +332,7 @@ class Node extends HiveObject with Keyable {
332 body: jsonBody,
333 );
334
231 -
335 +
336 final resBody = json.decode(response.body) as Map<String, dynamic>;
337
338 return resBody['result']['height'] != null;
cw_core/lib/node_legacy.dart new
+237
@@ -0,0 +1,237 @@
1 +import 'dart:io';
2 +import 'package:cw_core/keyable.dart';
3 +import 'package:cw_core/node_list.dart';
4 +import 'package:cw_core/utils/proxy_socket/abstract.dart';
5 +import 'package:cw_core/utils/proxy_wrapper.dart';
6 +import 'package:cw_core/utils/print_verbose.dart';
7 +import 'dart:convert';
8 +import 'package:hive/hive.dart';
9 +import 'package:cw_core/hive_type_ids.dart';
10 +import 'package:cw_core/wallet_type.dart';
11 +import 'dart:math' as math;
12 +import 'package:convert/convert.dart';
13 +
14 +import 'package:crypto/crypto.dart';
15 +
16 +import 'cake_hive.dart';
17 +import 'node.dart' as node_new;
18 +
19 +part "node_legacy.g.dart";
20 +
21 +Future<void> performNodeHiveMigration() async {
22 + if(!CakeHive.isAdapterRegistered(Node.typeId)) {
23 + CakeHive.registerAdapter(NodeAdapter());
24 + }
25 +
26 + final nodeBox = await CakeHive.openBox<Node>(Node.boxName);
27 + final powNodeBox = await CakeHive.openBox<Node>(Node.boxName+"pow");
28 + final builtinNodes = await loadAllDefaultNodes();
29 + final builtinPowNodes = await loadDefaultNanoPowNodes();
30 + await Node.migrateAllToSqlite(nodeBox, powNodeBox, builtinNodes, builtinPowNodes);
31 +
32 +
33 +}
34 +
35 +Uri createUriFromElectrumAddress(String address, String path) =>
36 + Uri.tryParse('tcp://$address$path')!;
37 +
38 +@HiveType(typeId: Node.typeId)
39 +class Node extends HiveObject with Keyable {
40 + Node({
41 + this.label,
42 + this.login,
43 + this.password,
44 + this.useSSL,
45 + this.trusted = false,
46 + this.socksProxyAddress,
47 + this.path = '',
48 + this.isEnabledForAutoSwitching = false,
49 + String? uri,
50 + WalletType? type,
51 + }) {
52 + if (uri != null) {
53 + uriRaw = uri;
54 + }
55 + if (type != null) {
56 + this.type = type;
57 + }
58 + }
59 +
60 + static Future<void> migrateAllToSqlite(Box<Node> nodeBox, Box<Node> powNodeBox,
61 + List<node_new.Node> defaultNodes, List<node_new.Node> defaultPowNodes) async {
62 + final list = nodeBox.values.toList();
63 + final powList = powNodeBox.values.toList();
64 + for (final node in list) {
65 + if(defaultNodes.any((item)=>item.uri == node.uri)) {
66 + // default nodes will be added by validateBuiltinNodes(), no need to migrate them.
67 + await node.delete();
68 + continue;
69 + }
70 + await node.migrateToSqlite(
71 + isPow: false,
72 + isBuiltin: false,
73 + isOfficial: false);
74 + await node.delete();
75 + }
76 + for (final node in powList) {
77 + if(defaultPowNodes.any((item)=>item.uri == node.uri)) {
78 + await node.delete();
79 + continue;
80 + }
81 + await node.migrateToSqlite(
82 + isPow: true,
83 + isBuiltin: false,
84 + isOfficial: false);
85 + await node.delete();
86 + }
87 + }
88 +
89 + Future<void> migrateToSqlite({required bool isPow, required bool isBuiltin, required bool isOfficial}) async {
90 + final newNode = node_new.Node(
91 + id: key as int,
92 + login: login,
93 + label: label,
94 + password: password,
95 + type: type,
96 + useSSL: useSSL,
97 + trusted: trusted,
98 + socksProxyAddress: socksProxyAddress,
99 + isPow: isPow,
100 + path: path,
101 + uri: uriRaw,
102 + isEnabledForAutoSwitching: isEnabledForAutoSwitching,
103 + isOfficial: isOfficial,
104 + isBuiltin: isBuiltin,
105 + );
106 + await newNode.save();
107 + }
108 +
109 +
110 + Node.fromMap(Map<String, Object?> map)
111 + : uriRaw = map['uri'] as String? ?? '',
112 + path = map['path'] as String? ?? '',
113 + login = map['login'] as String?,
114 + label = map['label'] as String?,
115 + password = map['password'] as String?,
116 + useSSL = map['useSSL'] as bool?,
117 + trusted = map['trusted'] as bool? ?? false,
118 + socksProxyAddress = map['socksProxyPort'] as String?,
119 + isEnabledForAutoSwitching = map['isEnabledForAutoSwitching'] as bool? ?? false;
120 +
121 + static const typeId = NODE_TYPE_ID;
122 + static const boxName = 'Nodes';
123 +
124 + @HiveField(0, defaultValue: '')
125 + late String uriRaw;
126 +
127 + @HiveField(1)
128 + String? login;
129 +
130 + @HiveField(2)
131 + String? password;
132 +
133 + @HiveField(3, defaultValue: 0)
134 + late int typeRaw;
135 +
136 + @HiveField(4)
137 + bool? useSSL;
138 +
139 + @HiveField(5, defaultValue: false)
140 + bool trusted;
141 +
142 + @HiveField(6)
143 + String? socksProxyAddress;
144 +
145 + @HiveField(7, defaultValue: '')
146 + String? path;
147 +
148 + @HiveField(8)
149 + bool? isElectrs;
150 +
151 + @HiveField(9)
152 + bool? supportsSilentPayments;
153 +
154 + @HiveField(10)
155 + bool? supportsMweb;
156 +
157 + @HiveField(11, defaultValue: false)
158 + bool isEnabledForAutoSwitching;
159 +
160 + @HiveField(12, defaultValue: '')
161 + String? label;
162 +
163 + bool get isSSL => useSSL ?? false;
164 +
165 + bool get useSocksProxy => socksProxyAddress == null ? false : socksProxyAddress!.isNotEmpty;
166 +
167 + Uri get uri {
168 + switch (type) {
169 + case WalletType.monero:
170 + case WalletType.zcash:
171 + case WalletType.haven:
172 + case WalletType.wownero:
173 + return Uri.http(uriRaw, '');
174 + case WalletType.bitcoin:
175 + case WalletType.litecoin:
176 + case WalletType.bitcoinCash:
177 + case WalletType.dogecoin:
178 + return createUriFromElectrumAddress(uriRaw, path!);
179 + case WalletType.nano:
180 + case WalletType.banano:
181 + case WalletType.ethereum:
182 + case WalletType.polygon:
183 + case WalletType.base:
184 + case WalletType.bsc:
185 + case WalletType.arbitrum:
186 + case WalletType.solana:
187 + case WalletType.tron:
188 + case WalletType.zano:
189 + case WalletType.decred:
190 + return Uri.parse(
191 + "http${isSSL ? "s" : ""}://$uriRaw${path!.startsWith("/") || path!.isEmpty ? path : "/$path"}");
192 + case WalletType.none:
193 + throw Exception('Unexpected type ${type.toString()} for Node uri');
194 + }
195 + }
196 +
197 + bool get isValidProxyAddress => socksProxyAddress?.contains(':') ?? false;
198 +
199 + @override
200 + bool operator ==(other) =>
201 + other is Node &&
202 + (other.uriRaw == uriRaw &&
203 + other.login == login &&
204 + other.label == label &&
205 + other.password == password &&
206 + other.typeRaw == typeRaw &&
207 + other.useSSL == useSSL &&
208 + other.trusted == trusted &&
209 + other.socksProxyAddress == socksProxyAddress &&
210 + other.path == path);
211 +
212 + @override
213 + int get hashCode =>
214 + uriRaw.hashCode ^
215 + login.hashCode ^
216 + label.hashCode ^
217 + password.hashCode ^
218 + typeRaw.hashCode ^
219 + useSSL.hashCode ^
220 + trusted.hashCode ^
221 + socksProxyAddress.hashCode ^
222 + path.hashCode;
223 +
224 + @override
225 + dynamic get keyIndex {
226 + _keyIndex ??= key;
227 + return _keyIndex;
228 + }
229 +
230 + WalletType get type => deserializeFromInt(typeRaw);
231 +
232 + set type(WalletType type) => typeRaw = serializeToInt(type);
233 +
234 + dynamic _keyIndex;
235 +
236 +
237 +}
\ No newline at end of file
cw_core/lib/node_list.dart new
+188
@@ -0,0 +1,188 @@
1 +import 'package:flutter/services.dart';
2 +import 'package:hive/hive.dart';
3 +import "package:yaml/yaml.dart";
4 +import 'package:cw_core/node.dart';
5 +import 'package:cw_core/wallet_type.dart';
6 +
7 +Future<List<Node>> loadDefaultNodes(WalletType type) async {
8 + String path;
9 + switch (type) {
10 + case WalletType.monero:
11 + path = 'assets/node_list.yml';
12 + break;
13 + case WalletType.bitcoin:
14 + path = 'assets/bitcoin_electrum_server_list.yml';
15 + break;
16 + case WalletType.litecoin:
17 + path = 'assets/litecoin_electrum_server_list.yml';
18 + break;
19 + case WalletType.haven:
20 + path = 'assets/haven_node_list.yml';
21 + break;
22 + // TODO: (refactoring) each wallet would have its path, so `wallet.nodePath` would be decided based on chain id in Evm wallet
23 + case WalletType.ethereum:
24 + path = 'assets/ethereum_server_list.yml';
25 + break;
26 + case WalletType.nano:
27 + path = 'assets/nano_node_list.yml';
28 + break;
29 + case WalletType.bitcoinCash:
30 + path = 'assets/bitcoin_cash_electrum_server_list.yml';
31 + break;
32 + case WalletType.polygon:
33 + path = 'assets/polygon_node_list.yml';
34 + break;
35 + case WalletType.solana:
36 + path = 'assets/solana_node_list.yml';
37 + break;
38 + case WalletType.tron:
39 + path = 'assets/tron_node_list.yml';
40 + break;
41 + case WalletType.wownero:
42 + path = 'assets/wownero_node_list.yml';
43 + break;
44 + case WalletType.zano:
45 + path = 'assets/zano_node_list.yml';
46 + break;
47 + case WalletType.decred:
48 + path = 'assets/decred_node_list.yml';
49 + break;
50 + case WalletType.dogecoin:
51 + path = 'assets/dogecoin_electrum_server_list.yml';
52 + break;
53 + case WalletType.base:
54 + path = 'assets/base_node_list.yml';
55 + break;
56 + case WalletType.arbitrum:
57 + path = 'assets/arbitrum_node_list.yml';
58 + break;
59 + case WalletType.zcash:
60 + path = 'assets/zcash_node_list.yml';
61 + break;
62 + case WalletType.bsc:
63 + path = 'assets/bsc_node_list.yml';
64 + break;
65 + case WalletType.banano:
66 + case WalletType.none:
67 + path = '';
68 + break;
69 + }
70 +
71 + final nodesRaw = await rootBundle.loadString(path);
72 + final loadedNodes = loadYaml(nodesRaw) as YamlList;
73 + final nodes = <Node>[];
74 +
75 + for (final raw in loadedNodes) {
76 + if (raw is Map) {
77 + final map = Map.from(raw);
78 + map["isBuiltin"] = 1;
79 + map["isOfficial"] = ((map["isOfficial"] as bool? ?? false) ? 1 : 0);
80 + map["isDefault"] = ((map["isDefault"] as bool? ?? false) ? 1 : 0);
81 + final node = Node.fromMap(Map<String, Object>.from(map));
82 + node.type = type;
83 + nodes.add(node);
84 + }
85 + }
86 +
87 + return nodes;
88 +}
89 +
90 +Future<List<Node>> loadDefaultNanoPowNodes() async {
91 + final powNodesRaw = await rootBundle.loadString('assets/nano_pow_node_list.yml');
92 + final loadedPowNodes = loadYaml(powNodesRaw) as YamlList;
93 + final nodes = <Node>[];
94 +
95 + for (final raw in loadedPowNodes) {
96 + if (raw is Map) {
97 + final node = Node.fromMap(Map<String, Object>.from(raw));
98 + node.isPow = true;
99 + node.type = WalletType.nano;
100 + nodes.add(node);
101 + }
102 + }
103 +
104 + return nodes;
105 +}
106 +
107 +Future<List<Node>> loadAllDefaultNodes() async {
108 + final moneroNodes = await loadDefaultNodes(WalletType.monero);
109 + final bitcoinElectrumServerList = await loadDefaultNodes(WalletType.bitcoin);
110 + final litecoinElectrumServerList = await loadDefaultNodes(WalletType.litecoin);
111 + final bitcoinCashElectrumServerList = await loadDefaultNodes(WalletType.bitcoinCash);
112 + final havenNodes = await loadDefaultNodes(WalletType.haven);
113 + final ethereumNodes = await loadDefaultNodes(WalletType.ethereum);
114 + final nanoNodes = await loadDefaultNodes(WalletType.nano);
115 + final polygonNodes = await loadDefaultNodes(WalletType.polygon);
116 + final solanaNodes = await loadDefaultNodes(WalletType.solana);
117 + final tronNodes = await loadDefaultNodes(WalletType.tron);
118 + final decredNodes = await loadDefaultNodes(WalletType.decred);
119 + final zanoNodes = await loadDefaultNodes(WalletType.zano);
120 + final dogecoinElectrumServerList = await loadDefaultNodes(WalletType.dogecoin);
121 + final baseNodes = await loadDefaultNodes(WalletType.base);
122 + final arbitrumNodes = await loadDefaultNodes(WalletType.arbitrum);
123 + final zcashNodes = await loadDefaultNodes(WalletType.zcash);
124 + final bscNodes = await loadDefaultNodes(WalletType.bsc);
125 +
126 + return moneroNodes +
127 + bitcoinElectrumServerList +
128 + litecoinElectrumServerList +
129 + havenNodes +
130 + ethereumNodes +
131 + bitcoinCashElectrumServerList +
132 + nanoNodes +
133 + polygonNodes +
134 + solanaNodes +
135 + tronNodes +
136 + zanoNodes +
137 + decredNodes +
138 + dogecoinElectrumServerList +
139 + baseNodes +
140 + arbitrumNodes +
141 + zcashNodes +
142 + bscNodes;
143 +}
144 +
145 +Future<void> resetToDefault() async {
146 +
147 + final nodes = await loadAllDefaultNodes();
148 +
149 + final currentNodes = await Node.getAll();
150 +
151 + // after reset, nodes should retain the id to correspond with the ones in shared prefs.
152 + // alternative would be nuking the shared prefs on reset
153 + for (final node in nodes) {
154 + try {
155 + final curr = currentNodes.firstWhere(
156 + (item) => item.uri == node.uri && item.typeRaw == node.typeRaw,
157 + );
158 + node.id = curr.id;
159 + } catch(e) {}
160 +
161 + }
162 +
163 + await Node.deleteAll();
164 + for(final node in nodes) {
165 + await node.save();
166 + }
167 +}
168 +
169 +Future<void> resetPowToDefault() async {
170 + final nanoPowNodes = await loadDefaultNanoPowNodes();
171 + await Node.deleteAllPow();
172 + for(final node in nanoPowNodes) {
173 + node.save();
174 + }
175 +}
176 +
177 +Future<Node> getDefaultNodeFromFiles(WalletType type, {bool isPow = false}) async {
178 + final nodes = isPow ? await loadDefaultNanoPowNodes() : await loadDefaultNodes(type);
179 + try {
180 + return nodes.firstWhere((item)=>item.isDefault);
181 + } catch(e) {
182 + // ideally the yamls would always have a default, but this is better than nothing
183 + return nodes.first;
184 + }
185 +}
186 +
187 +
188 +
lib/core/node_switching_service.dart
+7 -9
@@ -14,7 +14,6 @@ class NodeSwitchingService {
14 NodeSwitchingService({
15 required this.appStore,
16 required this.settingsStore,
17 - required this.nodeSource,
17 });
18
19 static const int _healthCheckIntervalSeconds = 30;
@@ -38,7 +37,6 @@ class NodeSwitchingService {
37
38 final AppStore appStore;
39 final SettingsStore settingsStore;
41 - final Box<Node> nodeSource;
40
41 final Map<WalletType, List<dynamic>> _usedNodeKeys = {};
42
@@ -118,13 +116,13 @@ class NodeSwitchingService {
116 WalletType walletType,
117 ) async {
118 for (final node in nodes) {
121 - if (!_usedNodeKeys[walletType]!.contains(node.key)) {
119 + if (!_usedNodeKeys[walletType]!.contains(node.id)) {
120 final isActive = await node.requestNode();
121 if (isActive) {
122 return node;
123 } else {
124 printV('Node ${node.uriRaw} is not active. Marking as used.');
127 - _usedNodeKeys[walletType]!.add(node.key);
125 + _usedNodeKeys[walletType]!.add(node.id);
126 }
127 }
128 }
@@ -157,7 +155,7 @@ class NodeSwitchingService {
155 final currentNode = settingsStore.getCurrentNode(nodeWalletType, chainId: chainId);
156
157 // Get all trusted nodes for this wallet type
160 - final trustedNodes = nodeSource.values
158 + final trustedNodes = (await Node.getAll())
159 .where((node) => node.type == nodeWalletType && node.isEnabledForAutoSwitching)
160 .toList();
161
@@ -171,8 +169,8 @@ class NodeSwitchingService {
169 _usedNodeKeys.putIfAbsent(nodeWalletType, () => []);
170
171 // Add current node to used list if not already there
174 - if (!_usedNodeKeys[nodeWalletType]!.contains(currentNode.key)) {
175 - _usedNodeKeys[nodeWalletType]!.add(currentNode.key);
172 + if (!_usedNodeKeys[nodeWalletType]!.contains(currentNode.id)) {
173 + _usedNodeKeys[nodeWalletType]!.add(currentNode.id);
174 }
175
176 // Try to find an active unused node
@@ -199,8 +197,8 @@ class NodeSwitchingService {
197 }
198
199 // Ensure the selected node is marked as used
202 - if (!_usedNodeKeys[nodeWalletType]!.contains(nextNode.key)) {
203 - _usedNodeKeys[nodeWalletType]!.add(nextNode.key);
200 + if (!_usedNodeKeys[nodeWalletType]!.contains(nextNode.id)) {
201 + _usedNodeKeys[nodeWalletType]!.add(nextNode.id);
202 }
203
204 printV(
lib/di.dart
+19 -26
@@ -326,8 +326,8 @@ import 'src/screens/buy/buy_sell_page.dart';
326 final getIt = GetIt.instance;
327
328 var _isSetupFinished = false;
329 -late Box<Node> _nodeSource;
330 -late Box<Node> _powNodeSource;
329 +// late Box<Node> _nodeSource;
330 +// late Box<Node> _powNodeSource;
331 late Box<Contact> _contactSource;
332 late Box<Template> _templates;
333 late Box<ExchangeTemplate> _exchangeTemplates;
@@ -337,8 +337,6 @@ late Box<UnspentCoinsInfo> _unspentCoinsInfoSource;
337 late Box<PayjoinSession> _payjoinSessionSource;
338 late Box<AnonpayInvoiceInfo> _anonpayInvoiceInfoSource;
339 Future<void> setup({
340 - required Box<Node> nodeSource,
341 - required Box<Node> powNodeSource,
340 required Box<Contact> contactSource,
341 required Box<Template> templates,
342 required Box<ExchangeTemplate> exchangeTemplates,
@@ -350,8 +348,6 @@ Future<void> setup({
348 required SecureStorage secureStorage,
349 required GlobalKey<NavigatorState> navigatorKey,
350 }) async {
353 - _nodeSource = nodeSource;
354 - _powNodeSource = powNodeSource;
351 _contactSource = contactSource;
352 _templates = templates;
353 _exchangeTemplates = exchangeTemplates;
@@ -376,8 +372,6 @@ Future<void> setup({
372 (secrets.wyreAccountId.isNotEmpty);
373
374 final settingsStore = await SettingsStoreBase.load(
379 - nodeSource: _nodeSource,
380 - powNodeSource: _powNodeSource,
375 isBitcoinBuyEnabled: isBitcoinBuyEnabled,
376 );
377
@@ -385,18 +379,16 @@ Future<void> setup({
379 return;
380 }
381
388 - getIt.registerFactory<Box<Node>>(() => _nodeSource);
389 - getIt.registerFactory<Box<Node>>(() => _powNodeSource, instanceName: Node.boxName + "pow");
382
383 getIt.registerSingleton(AuthenticationStore());
384 getIt.registerSingleton<WalletListStore>(WalletListStore());
393 - getIt.registerSingleton(NodeListStoreBase.instance);
385 + // getIt.registerSingleton(NodeListStoreBase.instance);
386 getIt.registerSingleton<SettingsStore>(settingsStore);
387 getIt.registerSingleton<AppStore>(AppStore(
388 authenticationStore: getIt.get<AuthenticationStore>(),
389 walletList: getIt.get<WalletListStore>(),
390 settingsStore: getIt.get<SettingsStore>(),
399 - nodeListStore: getIt.get<NodeListStore>(),
391 + // nodeListStore: getIt.get<NodeListStore>(),
392 themeStore: getIt.get<ThemeStore>()));
393 getIt.registerSingleton<TradesStore>(
394 TradesStore(appStore: getIt.get<AppStore>()));
@@ -1126,22 +1118,22 @@ Future<void> setup({
1118
1119 getIt.registerFactory(() => AddressListPage(getIt.get<WalletAddressListViewModel>()));
1120
1121 + getIt.registerLazySingleton(() {
1122 + final appStore = getIt.get<AppStore>();
1123 + return NodeListViewModel(appStore);
1124 + });
1125 +
1126 getIt.registerFactoryParam<NewAddressesPage, bool, void>(
1130 - (showHidden, _) => NewAddressesPage(
1127 + (showHidden, _) => NewAddressesPage(
1128 showHidden: showHidden,
1129 addressListViewModel: getIt<WalletAddressListViewModel>(),
1130 dashboardViewModel: getIt<DashboardViewModel>(),
1131 ),
1132 );
1133
1137 - getIt.registerFactory(() {
1134 + getIt.registerLazySingleton(() {
1135 final appStore = getIt.get<AppStore>();
1139 - return NodeListViewModel(_nodeSource, appStore);
1140 - });
1141 -
1142 - getIt.registerFactory(() {
1143 - final appStore = getIt.get<AppStore>();
1144 - return PowNodeListViewModel(_powNodeSource, appStore);
1136 + return PowNodeListViewModel(appStore);
1137 });
1138
1139 getIt.registerFactory(() => ConnectionSyncViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!));
@@ -1184,12 +1176,14 @@ Future<void> setup({
1176 final WalletType type = args['type'] as WalletType? ?? getIt.get<AppStore>().wallet!.type;
1177 final bool isPow = args['isPow'] as bool? ?? false;
1178 final Node? editingNode = args['editingNode'] as Node?;
1187 - final nodeSourceArgs = isPow ? _powNodeSource : _nodeSource;
1179 return NodeCreateOrEditViewModel(
1189 - nodeSourceArgs,
1190 - type,
1191 - editingNode,
1192 - getIt.get<SettingsStore>());
1180 + isPow,
1181 + getIt.get<NodeListViewModel>(),
1182 + getIt.get<PowNodeListViewModel>(),
1183 + type,
1184 + getIt.get<SettingsStore>(),
1185 + editingNode: editingNode
1186 + );
1187 }
1188 );
1189
@@ -1791,7 +1785,6 @@ Future<void> setup({
1785 getIt.registerLazySingleton(() => NodeSwitchingService(
1786 appStore: getIt.get<AppStore>(),
1787 settingsStore: getIt.get<SettingsStore>(),
1794 - nodeSource: _nodeSource,
1788 ));
1789
1790 getIt.registerFactoryParam<BridgeAmountPage, CryptoCurrency, void>(
lib/entities/default_settings_migration.dart
+119 -372
@@ -18,6 +18,7 @@ import 'package:cake_wallet/wownero/wownero.dart';
18 import 'package:collection/collection.dart';
19 import 'package:cw_core/node.dart';
20 import 'package:cake_wallet/entities/sync_status_display_mode.dart';
21 +import 'package:cw_core/node_list.dart';
22 import 'package:cw_core/pathForWallet.dart';
23 import 'package:cw_core/root_dir.dart';
24 import 'package:cw_core/spl_token.dart';
@@ -61,8 +62,6 @@ Future<void> defaultSettingsMigration(
62 {required int version,
63 required SharedPreferences sharedPreferences,
64 required SecureStorage secureStorage,
64 - required Box<Node> nodes,
65 - required Box<Node> powNodes,
65 required Box<Contact> contactSource,
66 required Box<HavenSeedStore> havenSeedStore}) async {
67 if (Platform.isIOS) {
@@ -70,7 +69,7 @@ Future<void> defaultSettingsMigration(
69 }
70
71 // check current nodes for nullability regardless of the version
73 - await checkCurrentNodes(nodes, powNodes, sharedPreferences);
72 + // await checkCurrentNodes(sharedPreferences);
73
74 final isNewInstall =
75 sharedPreferences.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) == null;
@@ -103,10 +102,9 @@ Future<void> defaultSettingsMigration(
102 await sharedPreferences.setInt(
103 PreferencesKey.currentBalanceDisplayModeKey, BalanceDisplayMode.availableBalance.raw);
104 await sharedPreferences.setBool('save_recipient_address', true);
106 - await resetToDefault(nodes);
105 + await resetToDefault();
106
107 await _changeDefaultNode(
109 - nodes: nodes,
108 sharedPreferences: sharedPreferences,
109 type: WalletType.monero,
110 currentNodePreferenceKey: PreferencesKey.currentNodeIdKey,
@@ -114,30 +112,26 @@ Future<void> defaultSettingsMigration(
112 trusted: true,
113 );
114 await _changeDefaultNode(
117 - nodes: nodes,
115 sharedPreferences: sharedPreferences,
116 type: WalletType.bitcoin,
117 currentNodePreferenceKey: PreferencesKey.currentBitcoinElectrumSererIdKey,
118 useSSL: true,
119 );
120 await _changeDefaultNode(
124 - nodes: nodes,
121 sharedPreferences: sharedPreferences,
122 type: WalletType.litecoin,
123 currentNodePreferenceKey: PreferencesKey.currentLitecoinElectrumSererIdKey,
124 useSSL: true,
125 );
126 await _changeDefaultNode(
131 - nodes: nodes,
127 sharedPreferences: sharedPreferences,
128 type: WalletType.haven,
129 currentNodePreferenceKey: PreferencesKey.currentHavenNodeIdKey,
130 );
131 break;
132 case 2:
138 - await replaceNodesMigration(nodes: nodes);
133 + await replaceNodesMigration();
134 await _changeDefaultNode(
140 - nodes: nodes,
135 sharedPreferences: sharedPreferences,
136 type: WalletType.monero,
137 newDefaultUri: newCakeWalletMoneroUri,
@@ -152,13 +146,12 @@ Future<void> defaultSettingsMigration(
146 );
147 break;
148 case 3:
155 - await updateNodeTypes(nodes: nodes);
156 - await addWalletNodeList(nodes: nodes, type: WalletType.bitcoin);
149 + await updateNodeTypes();
150 + await addWalletNodeList(type: WalletType.bitcoin);
151
152 break;
153 case 4:
154 await _changeDefaultNode(
161 - nodes: nodes,
155 sharedPreferences: sharedPreferences,
156 type: WalletType.bitcoin,
157 newDefaultUri: newCakeWalletBitcoinUri,
@@ -185,7 +178,6 @@ Future<void> defaultSettingsMigration(
178
179 case 11:
180 await _changeDefaultNode(
188 - nodes: nodes,
181 sharedPreferences: sharedPreferences,
182 type: WalletType.monero,
183 newDefaultUri: newCakeWalletMoneroUri,
@@ -196,38 +188,35 @@ Future<void> defaultSettingsMigration(
188 break;
189
190 case 12:
199 - await checkCurrentNodes(nodes, powNodes, sharedPreferences);
191 + // await checkCurrentNodes(sharedPreferences);
192 break;
193
194 case 13:
203 - await resetBitcoinElectrumServer(nodes, sharedPreferences);
195 + await resetBitcoinElectrumServer(sharedPreferences);
196 break;
197
198 case 15:
207 - await addWalletNodeList(nodes: nodes, type: WalletType.litecoin);
199 + await addWalletNodeList(type: WalletType.litecoin);
200 await _changeDefaultNode(
209 - nodes: nodes,
201 sharedPreferences: sharedPreferences,
202 type: WalletType.litecoin,
203 currentNodePreferenceKey: PreferencesKey.currentLitecoinElectrumSererIdKey,
204 );
214 - await checkCurrentNodes(nodes, powNodes, sharedPreferences);
205 + // await checkCurrentNodes(sharedPreferences);
206 break;
207
208 case 16:
218 - await addWalletNodeList(nodes: nodes, type: WalletType.haven);
209 + await addWalletNodeList(type: WalletType.haven);
210 await _changeDefaultNode(
220 - nodes: nodes,
211 sharedPreferences: sharedPreferences,
212 type: WalletType.haven,
213 currentNodePreferenceKey: PreferencesKey.currentHavenNodeIdKey,
214 );
225 - await checkCurrentNodes(nodes, powNodes, sharedPreferences);
215 + // await checkCurrentNodes(sharedPreferences);
216 break;
217
218 case 17:
219 await _changeDefaultNode(
230 - nodes: nodes,
220 sharedPreferences: sharedPreferences,
221 type: WalletType.haven,
222 currentNodePreferenceKey: PreferencesKey.currentHavenNodeIdKey,
@@ -235,7 +224,7 @@ Future<void> defaultSettingsMigration(
224 break;
225
226 case 18:
238 - addWalletNodeList(nodes: nodes, type: WalletType.monero);
227 + addWalletNodeList(type: WalletType.monero);
228 break;
229
230 case 19:
@@ -245,25 +234,22 @@ Future<void> defaultSettingsMigration(
234 await migrateExchangeStatus(sharedPreferences);
235 break;
236 case 21:
248 - await addWalletNodeList(nodes: nodes, type: WalletType.ethereum);
237 + await addWalletNodeList(type: WalletType.ethereum);
238 await _changeDefaultNode(
250 - nodes: nodes,
239 sharedPreferences: sharedPreferences,
240 type: WalletType.ethereum,
241 currentNodePreferenceKey: PreferencesKey.currentEthereumNodeIdKey,
242 );
243 break;
244 case 22:
257 - await addWalletNodeList(nodes: nodes, type: WalletType.nano);
258 - await addNanoPowNodeList(nodes: powNodes);
245 + await addWalletNodeList(type: WalletType.nano);
246 + await addNanoPowNodeList();
247 await _changeDefaultNode(
260 - nodes: nodes,
248 sharedPreferences: sharedPreferences,
249 type: WalletType.nano,
250 currentNodePreferenceKey: PreferencesKey.currentNanoNodeIdKey,
251 );
252 await _changeDefaultNode(
266 - nodes: powNodes,
253 sharedPreferences: sharedPreferences,
254 type: WalletType.nano,
255 currentNodePreferenceKey: PreferencesKey.currentNanoPowNodeIdKey,
@@ -271,18 +257,16 @@ Future<void> defaultSettingsMigration(
257 );
258 break;
259 case 23:
274 - await addWalletNodeList(nodes: nodes, type: WalletType.bitcoinCash);
260 + await addWalletNodeList(type: WalletType.bitcoinCash);
261 await _changeDefaultNode(
276 - nodes: nodes,
262 sharedPreferences: sharedPreferences,
263 type: WalletType.bitcoinCash,
264 currentNodePreferenceKey: PreferencesKey.currentBitcoinCashNodeIdKey,
265 );
266 break;
267 case 24:
283 - await addWalletNodeList(nodes: nodes, type: WalletType.polygon);
268 + await addWalletNodeList(type: WalletType.polygon);
269 await _changeDefaultNode(
285 - nodes: nodes,
270 sharedPreferences: sharedPreferences,
271 type: WalletType.polygon,
272 currentNodePreferenceKey: PreferencesKey.currentPolygonNodeIdKey,
@@ -299,9 +283,8 @@ Future<void> defaultSettingsMigration(
283 // await insecureStorageMigration(secureStorage: secureStorage, sharedPreferences: sharedPreferences);
284 break;
285 case 27:
302 - await addWalletNodeList(nodes: nodes, type: WalletType.solana);
286 + await addWalletNodeList( type: WalletType.solana);
287 await _changeDefaultNode(
304 - nodes: nodes,
288 sharedPreferences: sharedPreferences,
289 type: WalletType.solana,
290 currentNodePreferenceKey: PreferencesKey.currentSolanaNodeIdKey,
@@ -313,7 +296,6 @@ Future<void> defaultSettingsMigration(
296 break;
297 case 29:
298 await _changeDefaultNode(
316 - nodes: nodes,
299 sharedPreferences: sharedPreferences,
300 type: WalletType.bitcoin,
301 newDefaultUri: newCakeWalletBitcoinUri,
@@ -326,25 +308,23 @@ Future<void> defaultSettingsMigration(
308 await disableServiceStatusFiatDisabled(sharedPreferences);
309 break;
310 case 31:
329 - await updateNanoNodeList(nodes: nodes);
311 + await updateNanoNodeList();
312 break;
313 case 32:
314 await updateBtcNanoWalletInfos();
315 break;
316 case 33:
335 - await addWalletNodeList(nodes: nodes, type: WalletType.tron);
317 + await addWalletNodeList(type: WalletType.tron);
318 await _changeDefaultNode(
337 - nodes: nodes,
319 sharedPreferences: sharedPreferences,
320 type: WalletType.tron,
321 currentNodePreferenceKey: PreferencesKey.currentTronNodeIdKey,
322 );
323 break;
324 case 34:
344 - addWalletNodeList(nodes: nodes, type: WalletType.bitcoin);
325 + addWalletNodeList(type: WalletType.bitcoin);
326 case 35:
327 await _changeDefaultNode(
347 - nodes: nodes,
328 sharedPreferences: sharedPreferences,
329 type: WalletType.bitcoin,
330 newDefaultUri: newCakeWalletBitcoinUri,
@@ -354,9 +334,8 @@ Future<void> defaultSettingsMigration(
334 );
335 break;
336 case 36:
357 - await addWalletNodeList(nodes: nodes, type: WalletType.wownero);
337 + await addWalletNodeList(type: WalletType.wownero);
338 await _changeDefaultNode(
359 - nodes: nodes,
339 sharedPreferences: sharedPreferences,
340 type: WalletType.wownero,
341 currentNodePreferenceKey: PreferencesKey.currentWowneroNodeIdKey,
@@ -370,9 +349,8 @@ Future<void> defaultSettingsMigration(
349 await fixBtcDerivationPaths();
350 break;
351 case 39:
373 - _fixNodesUseSSLFlag(nodes);
352 + _fixNodesUseSSLFlag();
353 await _changeDefaultNode(
375 - nodes: nodes,
354 sharedPreferences: sharedPreferences,
355 type: WalletType.nano,
356 newDefaultUri: nanoDefaultNodeUri,
@@ -382,7 +360,7 @@ Future<void> defaultSettingsMigration(
360 );
361 break;
362 case 40:
385 - await removeMoneroWorld(sharedPreferences: sharedPreferences, nodes: nodes);
363 + await removeMoneroWorld(sharedPreferences: sharedPreferences);
364 break;
365 case 41:
366 _changeExchangeProviderAvailability(
@@ -390,14 +368,14 @@ Future<void> defaultSettingsMigration(
368 providerName: "SwapTrade",
369 enabled: false,
370 );
393 - addWalletNodeList(nodes: nodes, type: WalletType.bitcoin);
394 - addWalletNodeList(nodes: nodes, type: WalletType.tron);
371 + addWalletNodeList(type: WalletType.bitcoin);
372 + addWalletNodeList(type: WalletType.tron);
373 break;
374 case 42:
397 - _fixNodesUseSSLFlag(nodes);
375 + _fixNodesUseSSLFlag();
376 break;
377 case 43:
400 - _fixNodesUseSSLFlag(nodes);
378 + _fixNodesUseSSLFlag();
379 _changeExchangeProviderAvailability(
380 sharedPreferences,
381 providerName: "THORChain",
@@ -410,9 +388,8 @@ Future<void> defaultSettingsMigration(
388 );
389 break;
390 case 44:
413 - _fixNodesUseSSLFlag(nodes);
391 + _fixNodesUseSSLFlag();
392 await _changeDefaultNode(
415 - nodes: nodes,
393 sharedPreferences: sharedPreferences,
394 type: WalletType.bitcoin,
395 newDefaultUri: newCakeWalletBitcoinUri,
@@ -421,7 +398,6 @@ Future<void> defaultSettingsMigration(
398 oldUri: ['cakewallet.com'],
399 );
400 _changeDefaultNode(
424 - nodes: nodes,
401 sharedPreferences: sharedPreferences,
402 type: WalletType.tron,
403 newDefaultUri: tronDefaultNodeUri,
@@ -436,10 +412,9 @@ Future<void> defaultSettingsMigration(
412 case 45:
413 // await _backupHavenSeeds(havenSeedStore);
414
439 - addWalletNodeList(nodes: nodes, type: WalletType.polygon);
440 - addWalletNodeList(nodes: nodes, type: WalletType.ethereum);
415 + addWalletNodeList(type: WalletType.polygon);
416 + addWalletNodeList(type: WalletType.ethereum);
417 _changeDefaultNode(
442 - nodes: nodes,
418 sharedPreferences: sharedPreferences,
419 type: WalletType.tron,
420 newDefaultUri: tronDefaultNodeUri,
@@ -451,7 +426,6 @@ Future<void> defaultSettingsMigration(
426 ],
427 );
428 _changeDefaultNode(
454 - nodes: nodes,
429 sharedPreferences: sharedPreferences,
430 type: WalletType.solana,
431 newDefaultUri: solanaDefaultNodeUri,
@@ -461,10 +435,9 @@ Future<void> defaultSettingsMigration(
435 );
436 break;
437 case 46:
464 - await _fixNodesUseSSLFlag(nodes);
465 - await addWalletNodeList(nodes: nodes, type: WalletType.litecoin);
438 + await _fixNodesUseSSLFlag();
439 + await addWalletNodeList(type: WalletType.litecoin);
440 await _changeDefaultNode(
467 - nodes: nodes,
441 sharedPreferences: sharedPreferences,
442 type: WalletType.solana,
443 newDefaultUri: solanaDefaultNodeUri,
@@ -477,21 +450,18 @@ Future<void> defaultSettingsMigration(
450 ],
451 );
452 await _updateNode(
480 - nodes: nodes,
453 currentUri: "ethereum.publicnode.com",
454 newUri: "ethereum-rpc.publicnode.com",
455 useSSL: true,
456 );
457 await _updateNode(
486 - nodes: nodes,
458 currentUri: "polygon-bor.publicnode.com",
459 newUri: "polygon-bor-rpc.publicnode.com",
460 useSSL: true,
461 );
462 case 47:
492 - await addWalletNodeList(nodes: nodes, type: WalletType.zano);
463 + await addWalletNodeList(type: WalletType.zano);
464 await _changeDefaultNode(
494 - nodes: nodes,
465 sharedPreferences: sharedPreferences,
466 type: WalletType.zano,
467 currentNodePreferenceKey: PreferencesKey.currentZanoNodeIdKey,
@@ -508,9 +478,8 @@ Future<void> defaultSettingsMigration(
478 );
479 break;
480 case 48:
511 - await addWalletNodeList(nodes: nodes, type: WalletType.decred);
481 + await addWalletNodeList(type: WalletType.decred);
482 await _changeDefaultNode(
513 - nodes: nodes,
483 sharedPreferences: sharedPreferences,
484 type: WalletType.decred,
485 currentNodePreferenceKey: PreferencesKey.currentDecredNodeIdKey,
@@ -524,36 +493,32 @@ Future<void> defaultSettingsMigration(
493 );
494 break;
495 case 50:
527 - migrateExistingNodesToUseAutoSwitching(nodes: nodes, powNodes: powNodes);
496 + migrateExistingNodesToUseAutoSwitching();
497 break;
498 case 51:
499 _changeDefaultNode(
531 - nodes: nodes,
500 sharedPreferences: sharedPreferences,
501 type: WalletType.zano,
502 currentNodePreferenceKey: PreferencesKey.currentZanoNodeIdKey,
503 );
536 - await addWalletNodeList(nodes: nodes, type: WalletType.dogecoin);
504 + await addWalletNodeList(type: WalletType.dogecoin);
505 await _changeDefaultNode(
538 - nodes: nodes,
506 sharedPreferences: sharedPreferences,
507 type: WalletType.dogecoin,
508 currentNodePreferenceKey: PreferencesKey.currentDogecoinNodeIdKey,
509 );
510 break;
511 case 52:
545 - await addWalletNodeList(nodes: nodes, type: WalletType.base);
512 + await addWalletNodeList(type: WalletType.base);
513 await _changeDefaultNode(
547 - nodes: nodes,
514 sharedPreferences: sharedPreferences,
515 type: WalletType.base,
516 currentNodePreferenceKey: PreferencesKey.currentBaseNodeIdKey,
517 );
518 break;
553 - case 53:
554 - await addWalletNodeList(nodes: nodes, type: WalletType.arbitrum);
519 + case 53:
520 + await addWalletNodeList(type: WalletType.arbitrum);
521 await _changeDefaultNode(
556 - nodes: nodes,
522 sharedPreferences: sharedPreferences,
523 type: WalletType.arbitrum,
524 currentNodePreferenceKey: PreferencesKey.currentArbitrumNodeIdKey,
@@ -563,9 +528,8 @@ Future<void> defaultSettingsMigration(
528 await _backupWowneroSeeds(havenSeedStore);
529 break;
530 case 55:
566 - await addWalletNodeList(nodes: nodes, type: WalletType.zcash);
531 + await addWalletNodeList(type: WalletType.zcash);
532 await _changeDefaultNode(
568 - nodes: nodes,
533 sharedPreferences: sharedPreferences,
534 type: WalletType.zcash,
535 currentNodePreferenceKey: PreferencesKey.currentZcashNodeIdKey,
@@ -577,9 +541,8 @@ Future<void> defaultSettingsMigration(
541 case 57:
542 await _addXautTokenToExistingEthereumWallets();
543
580 - await addWalletNodeList(nodes: nodes, type: WalletType.bsc);
544 + await addWalletNodeList(type: WalletType.bsc);
545 await _changeDefaultNode(
582 - nodes: nodes,
546 sharedPreferences: sharedPreferences,
547 type: WalletType.bsc,
548 currentNodePreferenceKey: PreferencesKey.currentBscNodeIdKey,
@@ -624,13 +587,18 @@ Future<void> defaultSettingsMigration(
587 break;
588 case 65:
589 await _changeDefaultNode(
627 - nodes: nodes,
590 sharedPreferences: sharedPreferences,
591 type: WalletType.base,
592 currentNodePreferenceKey: PreferencesKey.currentBaseNodeIdKey,
593 oldUri: ['base.nownodes.io'],
594 );
595 break;
596 + case 66:
597 + await _changeDefaultNode(
598 + sharedPreferences: sharedPreferences,
599 + type: WalletType.arbitrum,
600 + currentNodePreferenceKey: PreferencesKey.currentArbitrumNodeIdKey,
601 + oldUri: ["arbitrum.nownodes.io"]);
602 default:
603 break;
604 }
@@ -647,12 +615,13 @@ Future<void> defaultSettingsMigration(
615 }
616
617 Future<void> _updateNode({
650 - required Box<Node> nodes,
618 required String currentUri,
619 String? newUri,
620 bool? useSSL,
621 }) async {
655 - for (Node node in nodes.values) {
622 + final nodes = await Node.getAll();
623 +
624 + for (Node node in nodes) {
625 if (node.uriRaw == currentUri) {
626 if (newUri != null) {
627 node.uriRaw = newUri;
@@ -668,7 +637,6 @@ Future<void> _updateNode({
637 /// generic function for changing any wallet default node
638 /// instead of making a new function for each change
639 Future<void> _changeDefaultNode({
671 - required Box<Node> nodes,
640 required SharedPreferences sharedPreferences,
641 required WalletType type,
642 required String currentNodePreferenceKey,
@@ -678,19 +646,21 @@ Future<void> _changeDefaultNode({
646 List<String>?
647 oldUri, // ignore, if you want to force replace the node regardless of the user's current node
648 }) async {
649 + List<Node> nodes = await Node.getAll();
650 +
651 final currentNodeId = sharedPreferences.getInt(currentNodePreferenceKey);
652 final bool shouldReplace;
653 if (currentNodeId == null) {
654 shouldReplace = true;
655 } else {
686 - final currentNode = nodes.values.firstWhere((node) => node.key == currentNodeId);
687 - shouldReplace = oldUri?.any((e) => currentNode.uriRaw.contains(e)) ?? true;
656 + final currentNode = nodes.firstWhereOrNull((node) => node.id == currentNodeId);
657 + shouldReplace = currentNode == null || oldUri?.any((e) => currentNode!.uriRaw.contains(e)) ?? true;
658 }
659
660 if (shouldReplace) {
691 - newDefaultUri ??= _getDefaultNodeUri(type);
661 + newDefaultUri ??= (await getDefaultNodeFromFiles(type)).uriRaw;
662 var newNodeId =
693 - nodes.values.firstWhereOrNull((element) => element.uriRaw == newDefaultUri)?.key;
663 + nodes.firstWhereOrNull((element) => element.uriRaw == newDefaultUri)?.id;
664
665 // new node doesn't exist, then add it
666 if (newNodeId == null) {
@@ -701,55 +671,11 @@ Future<void> _changeDefaultNode({
671 trusted: trusted,
672 );
673
704 - await nodes.add(newNode);
705 - newNodeId = newNode.key;
674 + await newNode.save();
675 + newNodeId = newNode.id;
676 }
677
708 - await sharedPreferences.setInt(currentNodePreferenceKey, newNodeId as int);
709 - }
710 -}
711 -
712 -String _getDefaultNodeUri(WalletType type) {
713 - switch (type) {
714 - case WalletType.monero:
715 - return newCakeWalletMoneroUri;
716 - case WalletType.bitcoin:
717 - return newCakeWalletBitcoinUri;
718 - case WalletType.litecoin:
719 - return cakeWalletLitecoinElectrumUri;
720 - case WalletType.haven:
721 - return havenDefaultNodeUri;
722 - case WalletType.ethereum:
723 - return ethereumDefaultNodeUri;
724 - case WalletType.nano:
725 - return nanoDefaultNodeUri;
726 - case WalletType.bitcoinCash:
727 - return cakeWalletBitcoinCashDefaultNodeUri;
728 - case WalletType.polygon:
729 - return polygonDefaultNodeUri;
730 - case WalletType.solana:
731 - return solanaDefaultNodeUri;
732 - case WalletType.tron:
733 - return tronDefaultNodeUri;
734 - case WalletType.wownero:
735 - return wowneroDefaultNodeUri;
736 - case WalletType.zano:
737 - return zanoDefaultNodeUri;
738 - case WalletType.decred:
739 - return decredDefaultUri;
740 - case WalletType.dogecoin:
741 - return dogecoinDefaultNodeUri;
742 - case WalletType.base:
743 - return baseDefaultNodeUri;
744 - case WalletType.arbitrum:
745 - return arbitrumDefaultNodeUri;
746 - case WalletType.bsc:
747 - return bscDefaultNodeUri;
748 - case WalletType.zcash:
749 - return zcashDefaultNodeUri;
750 - case WalletType.banano:
751 - case WalletType.none:
752 - return '';
678 + await sharedPreferences.setInt(currentNodePreferenceKey, newNodeId);
679 }
680 }
681
@@ -767,8 +693,9 @@ Future<void> _changeExchangeProviderAvailability(SharedPreferences sharedPrefere
693 );
694 }
695
770 -Future<void> _fixNodesUseSSLFlag(Box<Node> nodes) async {
771 - for (Node node in nodes.values) {
696 +Future<void> _fixNodesUseSSLFlag() async {
697 + final nodes = await Node.getAll();
698 + for (Node node in nodes) {
699 switch (node.uriRaw) {
700 case cakeWalletLitecoinElectrumUri:
701 case cakeWalletBitcoinElectrumUri:
@@ -781,7 +708,8 @@ Future<void> _fixNodesUseSSLFlag(Box<Node> nodes) async {
708 }
709 }
710
784 -Future<void> updateNanoNodeList({required Box<Node> nodes}) async {
711 +Future<void> updateNanoNodeList() async {
712 + final nodes = await Node.getAll();
713 final nodeList = await loadDefaultNodes(WalletType.nano);
714 var listOfNewEndpoints = <String>[
715 "app.natrium.io",
@@ -792,14 +720,14 @@ Future<void> updateNanoNodeList({required Box<Node> nodes}) async {
720 ];
721 // add new nodes:
722 for (final node in nodeList) {
795 - if (listOfNewEndpoints.contains(node.uriRaw) && !nodes.values.contains(node)) {
796 - await nodes.add(node);
723 + if (listOfNewEndpoints.contains(node.uriRaw) && !nodes.contains(node)) {
724 + await node.save();
725 }
726 }
727
728 // update the nautilus node:
729 final nautilusNode =
802 - nodes.values.firstWhereOrNull((element) => element.uriRaw == "node.perish.co");
730 + nodes.firstWhereOrNull((element) => element.uriRaw == "node.perish.co");
731 if (nautilusNode != null) {
732 nautilusNode.uriRaw = "node.nautilus.io";
733 nautilusNode.path = "/api";
@@ -916,16 +844,17 @@ Future<void> validateBitcoinSavedTransactionPriority(SharedPreferences sharedPre
844 }
845 }
846
919 -Future<void> replaceNodesMigration({required Box<Node> nodes}) async {
847 +Future<void> replaceNodesMigration() async {
848 final replaceNodes = <String, Node>{
849 'eu-node.cakewallet.io:18081':
922 - Node(uri: 'xmr-node-eu.cakewallet.com:18081', type: WalletType.monero),
850 + Node(uri: 'xmr-node-eu.cakewallet.com:18081', type: WalletType.monero),
851 'node.cakewallet.io:18081':
924 - Node(uri: 'xmr-node-usa-east.cakewallet.com:18081', type: WalletType.monero),
852 + Node(uri: 'xmr-node-usa-east.cakewallet.com:18081', type: WalletType.monero),
853 'node.xmr.ru:13666': Node(uri: 'node.monero.net:18081', type: WalletType.monero)
854 };
855
928 - nodes.values.forEach((Node node) async {
856 + List<Node> nodes = await Node.getAll();
857 + nodes.forEach((Node node) async {
858 final nodeToReplace = replaceNodes[node.uri];
859
860 if (nodeToReplace != null) {
@@ -937,16 +866,12 @@ Future<void> replaceNodesMigration({required Box<Node> nodes}) async {
866 });
867 }
868
940 -Node? getBitcoinTestnetDefaultElectrumServer({required Box<Node> nodes}) {
941 - return nodes.values
942 - .firstWhereOrNull((Node node) => node.uriRaw == publicBitcoinTestnetElectrumUri) ??
943 - nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoin);
944 -}
869 +Future<Node?> getBitcoinTestnetDefaultElectrumServer()async {
870 + final nodes = await Node.getAll();
871
946 -Node? getDefaultNode({required Box<Node> nodes, required WalletType type}) {
947 - final defaultUri = _getDefaultNodeUri(type);
948 - return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == defaultUri) ??
949 - nodes.values.firstWhereOrNull((node) => node.type == type);
872 + return nodes
873 + .firstWhereOrNull((Node node) => node.uriRaw == publicBitcoinTestnetElectrumUri) ??
874 + nodes.firstWhereOrNull((node) => node.type == WalletType.bitcoin);
875 }
876
877 Future<void> insecureStorageMigration({
@@ -1057,8 +982,9 @@ Future<void> rewriteSecureStoragePin({required SecureStorage secureStorage}) asy
982 );
983 }
984
1060 -Future<void> updateNodeTypes({required Box<Node> nodes}) async {
1061 - nodes.values.forEach((node) async {
985 +Future<void> updateNodeTypes() async {
986 + List<Node> nodes = await Node.getAll();
987 + nodes.forEach((node) async {
988 if (node.type == null) {
989 node.type = WalletType.monero;
990 await node.save();
@@ -1146,206 +1072,13 @@ Future<void> updateBtcNanoWalletInfos() async {}
1072 // }
1073 // }
1074
1149 -Future<void> checkCurrentNodes(
1150 - Box<Node> nodeSource, Box<Node> powNodeSource, SharedPreferences sharedPreferences) async {
1151 - final currentMoneroNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
1152 - final currentBitcoinElectrumSeverId =
1153 - sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
1154 - final currentLitecoinElectrumSeverId =
1155 - sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
1156 - final currentHavenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
1157 - final currentEthereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
1158 - final currentPolygonNodeId = sharedPreferences.getInt(PreferencesKey.currentPolygonNodeIdKey);
1159 - final currentBaseNodeId = sharedPreferences.getInt(PreferencesKey.currentBaseNodeIdKey);
1160 - final currentArbitrumNodeId = sharedPreferences.getInt(PreferencesKey.currentArbitrumNodeIdKey);
1161 - final currentBscNodeId = sharedPreferences.getInt(PreferencesKey.currentBscNodeIdKey);
1162 - final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
1163 - final currentNanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoPowNodeIdKey);
1164 - final currentDecredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
1165 - final currentBitcoinCashNodeId =
1166 - sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
1167 - final currentDogecoinNodeId = sharedPreferences.getInt(PreferencesKey.currentDogecoinNodeIdKey);
1168 - final currentSolanaNodeId = sharedPreferences.getInt(PreferencesKey.currentSolanaNodeIdKey);
1169 - final currentTronNodeId = sharedPreferences.getInt(PreferencesKey.currentTronNodeIdKey);
1170 - final currentWowneroNodeId = sharedPreferences.getInt(PreferencesKey.currentWowneroNodeIdKey);
1171 - final currentZanoNodeId = sharedPreferences.getInt(PreferencesKey.currentZanoNodeIdKey);
1172 - final currentZcashNodeId = sharedPreferences.getInt(PreferencesKey.currentZcashNodeIdKey);
1173 - final currentMoneroNode =
1174 - nodeSource.values.firstWhereOrNull((node) => node.key == currentMoneroNodeId);
1175 - final currentBitcoinElectrumServer =
1176 - nodeSource.values.firstWhereOrNull((node) => node.key == currentBitcoinElectrumSeverId);
1177 - final currentLitecoinElectrumServer =
1178 - nodeSource.values.firstWhereOrNull((node) => node.key == currentLitecoinElectrumSeverId);
1179 - final currentHavenNodeServer =
1180 - nodeSource.values.firstWhereOrNull((node) => node.key == currentHavenNodeId);
1181 - final currentEthereumNodeServer =
1182 - nodeSource.values.firstWhereOrNull((node) => node.key == currentEthereumNodeId);
1183 - final currentPolygonNodeServer =
1184 - nodeSource.values.firstWhereOrNull((node) => node.key == currentPolygonNodeId);
1185 - final currentBaseNodeServer =
1186 - nodeSource.values.firstWhereOrNull((node) => node.key == currentBaseNodeId);
1187 - final currentArbitrumNodeServer =
1188 - nodeSource.values.firstWhereOrNull((node) => node.key == currentArbitrumNodeId);
1189 - final currentBscNodeServer =
1190 - nodeSource.values.firstWhereOrNull((node) => node.key == currentBscNodeId);
1191 - final currentNanoNodeServer =
1192 - nodeSource.values.firstWhereOrNull((node) => node.key == currentNanoNodeId);
1193 - final currentDecredNodeServer =
1194 - nodeSource.values.firstWhereOrNull((node) => node.key == currentDecredNodeId);
1195 - final currentNanoPowNodeServer =
1196 - powNodeSource.values.firstWhereOrNull((node) => node.key == currentNanoPowNodeId);
1197 - final currentBitcoinCashNodeServer =
1198 - nodeSource.values.firstWhereOrNull((node) => node.key == currentBitcoinCashNodeId);
1199 - final currentDogecoinNodeServer =
1200 - nodeSource.values.firstWhereOrNull((node) => node.key == currentDogecoinNodeId);
1201 - final currentSolanaNodeServer =
1202 - nodeSource.values.firstWhereOrNull((node) => node.key == currentSolanaNodeId);
1203 - final currentTronNodeServer =
1204 - nodeSource.values.firstWhereOrNull((node) => node.key == currentTronNodeId);
1205 - final currentWowneroNodeServer =
1206 - nodeSource.values.firstWhereOrNull((node) => node.key == currentWowneroNodeId);
1207 - final currentZanoNode =
1208 - nodeSource.values.firstWhereOrNull((node) => node.key == currentZanoNodeId);
1209 - final currentZcashNode =
1210 - nodeSource.values.firstWhereOrNull((node) => node.key == currentZcashNodeId);
1211 -
1212 - if (currentMoneroNode == null) {
1213 - final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero);
1214 - await nodeSource.add(newCakeWalletNode);
1215 - await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, newCakeWalletNode.key as int);
1216 - }
1217 -
1218 - if (currentBitcoinElectrumServer == null) {
1219 - final cakeWalletElectrum = Node(
1220 - uri: cakeWalletBitcoinElectrumUri,
1221 - type: WalletType.bitcoin,
1222 - useSSL: false,
1223 - isEnabledForAutoSwitching: true);
1224 - await nodeSource.add(cakeWalletElectrum);
1225 - final cakeWalletElectrumTestnet =
1226 - Node(uri: publicBitcoinTestnetElectrumUri, type: WalletType.bitcoin, useSSL: false);
1227 - await nodeSource.add(cakeWalletElectrumTestnet);
1228 - await sharedPreferences.setInt(
1229 - PreferencesKey.currentBitcoinElectrumSererIdKey, cakeWalletElectrum.key as int);
1230 - }
1231 -
1232 - if (currentLitecoinElectrumServer == null) {
1233 - final cakeWalletElectrum =
1234 - Node(uri: cakeWalletLitecoinElectrumUri, type: WalletType.litecoin, useSSL: false);
1235 - await nodeSource.add(cakeWalletElectrum);
1236 - await sharedPreferences.setInt(
1237 - PreferencesKey.currentLitecoinElectrumSererIdKey, cakeWalletElectrum.key as int);
1238 - }
1239 -
1240 - if (currentHavenNodeServer == null) {
1241 - final node = Node(uri: havenDefaultNodeUri, type: WalletType.haven);
1242 - await nodeSource.add(node);
1243 - await sharedPreferences.setInt(PreferencesKey.currentHavenNodeIdKey, node.key as int);
1244 - }
1245 -
1246 - if (currentEthereumNodeServer == null) {
1247 - final node = Node(uri: ethereumDefaultNodeUri, type: WalletType.ethereum);
1248 - await nodeSource.add(node);
1249 - await sharedPreferences.setInt(PreferencesKey.currentEthereumNodeIdKey, node.key as int);
1250 - }
1251 -
1252 - if (currentNanoNodeServer == null) {
1253 - final node = Node(uri: nanoDefaultNodeUri, useSSL: true, type: WalletType.nano);
1254 - await nodeSource.add(node);
1255 - await sharedPreferences.setInt(PreferencesKey.currentNanoNodeIdKey, node.key as int);
1256 - }
1257 -
1258 - if (currentNanoPowNodeServer == null) {
1259 - Node? node = powNodeSource.values
1260 - .firstWhereOrNull((node) => node.uri.toString() == nanoDefaultPowNodeUri);
1261 - if (node == null) {
1262 - node = Node(uri: nanoDefaultPowNodeUri, useSSL: true, type: WalletType.nano);
1263 - await powNodeSource.add(node);
1264 - }
1265 - await sharedPreferences.setInt(PreferencesKey.currentNanoPowNodeIdKey, node.key as int);
1266 - }
1267 -
1268 - if (currentBitcoinCashNodeServer == null) {
1269 - final node =
1270 - Node(uri: cakeWalletBitcoinCashDefaultNodeUri, type: WalletType.bitcoinCash, useSSL: false);
1271 - await nodeSource.add(node);
1272 - await sharedPreferences.setInt(PreferencesKey.currentBitcoinCashNodeIdKey, node.key as int);
1273 - }
1274 -
1275 - if (currentDogecoinNodeServer == null) {
1276 - final node = Node(uri: dogecoinDefaultNodeUri, type: WalletType.dogecoin, useSSL: true);
1277 - await nodeSource.add(node);
1278 - await sharedPreferences.setInt(PreferencesKey.currentDogecoinNodeIdKey, node.key as int);
1279 - }
1280 -
1281 - if (currentPolygonNodeServer == null) {
1282 - final node = Node(uri: polygonDefaultNodeUri, type: WalletType.polygon);
1283 - await nodeSource.add(node);
1284 - await sharedPreferences.setInt(PreferencesKey.currentPolygonNodeIdKey, node.key as int);
1285 - }
1286 -
1287 - if (currentBaseNodeServer == null) {
1288 - final node = Node(uri: baseDefaultNodeUri, type: WalletType.base);
1289 - await nodeSource.add(node);
1290 - await sharedPreferences.setInt(PreferencesKey.currentBaseNodeIdKey, node.key as int);
1291 - }
1292 -
1293 - if (currentArbitrumNodeServer == null) {
1294 - final node = Node(uri: arbitrumDefaultNodeUri, type: WalletType.arbitrum);
1295 - await nodeSource.add(node);
1296 - await sharedPreferences.setInt(PreferencesKey.currentArbitrumNodeIdKey, node.key as int);
1297 - }
1298 -
1299 - if (currentBscNodeServer == null) {
1300 - final node = Node(uri: bscDefaultNodeUri, type: WalletType.bsc);
1301 - await nodeSource.add(node);
1302 - await sharedPreferences.setInt(PreferencesKey.currentBscNodeIdKey, node.key as int);
1303 - }
1304 -
1305 - if (currentSolanaNodeServer == null) {
1306 - final node = Node(uri: solanaDefaultNodeUri, type: WalletType.solana);
1307 - await nodeSource.add(node);
1308 - await sharedPreferences.setInt(PreferencesKey.currentSolanaNodeIdKey, node.key as int);
1309 - }
1310 -
1311 - if (currentTronNodeServer == null) {
1312 - final node = Node(uri: tronDefaultNodeUri, type: WalletType.tron);
1313 - await nodeSource.add(node);
1314 - await sharedPreferences.setInt(PreferencesKey.currentTronNodeIdKey, node.key as int);
1315 - }
1316 -
1317 - if (currentWowneroNodeServer == null) {
1318 - final node = Node(uri: wowneroDefaultNodeUri, type: WalletType.wownero);
1319 - await nodeSource.add(node);
1320 - await sharedPreferences.setInt(PreferencesKey.currentWowneroNodeIdKey, node.key as int);
1321 - }
1322 -
1323 - if (currentZanoNode == null) {
1324 - final node = Node(uri: zanoDefaultNodeUri, type: WalletType.zano);
1325 - await nodeSource.add(node);
1326 - await sharedPreferences.setInt(PreferencesKey.currentZanoNodeIdKey, node.key as int);
1327 - }
1328 -
1329 - if (currentDecredNodeServer == null) {
1330 - final node = Node(uri: decredDefaultUri, type: WalletType.decred);
1331 - await nodeSource.add(node);
1332 - await sharedPreferences.setInt(PreferencesKey.currentDecredNodeIdKey, node.key as int);
1333 - }
1334 -
1335 - if (currentZcashNode == null) {
1336 - final node = Node(uri: zcashDefaultNodeUri, type: WalletType.zcash, useSSL: true);
1337 - await nodeSource.add(node);
1338 - await sharedPreferences.setInt(PreferencesKey.currentZcashNodeIdKey, node.key as int);
1339 - }
1340 -}
1341 -
1342 -Future<void> resetBitcoinElectrumServer(
1343 - Box<Node> nodeSource, SharedPreferences sharedPreferences) async {
1075 +Future<void> resetBitcoinElectrumServer(SharedPreferences sharedPreferences) async {
1076 + final nodeSource = await Node.getAll();
1077 final currentElectrumSeverId =
1078 sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
1346 - final oldElectrumServer = nodeSource.values
1079 + final oldElectrumServer = nodeSource
1080 .firstWhereOrNull((node) => node.uri.toString().contains('electrumx.cakewallet.com'));
1348 - var cakeWalletNode = nodeSource.values
1081 + var cakeWalletNode = nodeSource
1082 .firstWhereOrNull((node) => node.uriRaw.toString() == cakeWalletBitcoinElectrumUri);
1083
1084 if (cakeWalletNode == null) {
@@ -1357,12 +1090,12 @@ Future<void> resetBitcoinElectrumServer(
1090 // final cakeWalletElectrumTestnet =
1091 // Node(uri: publicBitcoinTestnetElectrumUri, type: WalletType.bitcoin, useSSL: false);
1092 // await nodeSource.add(cakeWalletElectrumTestnet);
1360 - await nodeSource.add(cakeWalletNode);
1093 + await cakeWalletNode.save();
1094 }
1095
1363 - if (currentElectrumSeverId == oldElectrumServer?.key) {
1096 + if (currentElectrumSeverId == oldElectrumServer?.id) {
1097 await sharedPreferences.setInt(
1365 - PreferencesKey.currentBitcoinElectrumSererIdKey, cakeWalletNode.key as int);
1098 + PreferencesKey.currentBitcoinElectrumSererIdKey, cakeWalletNode.id);
1099 }
1100
1101 await oldElectrumServer?.delete();
@@ -1380,38 +1113,42 @@ Future<void> migrateExchangeStatus(SharedPreferences sharedPreferences) async {
1113 await sharedPreferences.remove(PreferencesKey.disableExchangeKey);
1114 }
1115
1383 -Future<void> addNanoPowNodeList({required Box<Node> nodes}) async {
1116 +Future<void> addNanoPowNodeList() async {
1117 final nodeList = await loadDefaultNanoPowNodes();
1118 + final nodes = await Node.getAllPow();
1119 for (var node in nodeList) {
1386 - if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) {
1387 - await nodes.add(node);
1120 + if (nodes.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) {
1121 + await node.save();
1122 }
1123 }
1124 }
1125
1392 -Node? getNanoDefaultPowNode({required Box<Node> nodes}) {
1393 - return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == nanoDefaultPowNodeUri) ??
1394 - nodes.values.firstWhereOrNull((node) => (node.type == WalletType.nano));
1126 +Future<Node?> getNanoDefaultPowNode() async {
1127 + final nodes = await Node.getAll();
1128 + return nodes.firstWhereOrNull((Node node) => node.uriRaw == nanoDefaultPowNodeUri) ??
1129 + nodes.firstWhereOrNull((node) => (node.type == WalletType.nano));
1130 }
1131
1397 -Future<void> addWalletNodeList({required Box<Node> nodes, required WalletType type}) async {
1132 +Future<void> addWalletNodeList({required WalletType type}) async {
1133 + final nodes = await Node.getAll();
1134 final List<Node> nodeList = await loadDefaultNodes(type);
1135 for (var node in nodeList) {
1400 - if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) {
1401 - await nodes.add(node);
1136 + if (nodes.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) {
1137 + await node.save();
1138 }
1139 }
1140 }
1141
1142 Future<void> removeMoneroWorld(
1407 - {required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
1143 + {required SharedPreferences sharedPreferences}) async {
1144 + final nodes = await Node.getAll();
1145 const cakeWalletMoneroNodeUriPattern = '.moneroworld.com';
1146 final currentMoneroNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
1410 - final currentMoneroNode = nodes.values.firstWhere((node) => node.key == currentMoneroNodeId);
1147 + final currentMoneroNode = nodes.firstWhere((node) => node.id == currentMoneroNodeId);
1148 final needToReplaceCurrentMoneroNode =
1149 currentMoneroNode.uri.toString().contains(cakeWalletMoneroNodeUriPattern);
1150
1414 - nodes.values.forEach((node) async {
1151 + nodes.forEach((node) async {
1152 if (node.type == WalletType.monero &&
1153 node.uri.toString().contains(cakeWalletMoneroNodeUriPattern)) {
1154 await node.delete();
@@ -1420,7 +1157,6 @@ Future<void> removeMoneroWorld(
1157
1158 if (needToReplaceCurrentMoneroNode) {
1159 await _changeDefaultNode(
1423 - nodes: nodes,
1160 sharedPreferences: sharedPreferences,
1161 type: WalletType.monero,
1162 newDefaultUri: newCakeWalletMoneroUri,
@@ -1430,8 +1166,7 @@ Future<void> removeMoneroWorld(
1166 }
1167 }
1168
1433 -Future<void> migrateExistingNodesToUseAutoSwitching(
1434 - {required Box<Node> nodes, required Box<Node> powNodes}) async {
1169 +Future<void> migrateExistingNodesToUseAutoSwitching() async {
1170 final listOfDefaultNodesWithAutoSwitching = [
1171 'bitcoincash.stackwallet.com:50002',
1172 'bch.aftrek.org:50002',
@@ -1465,12 +1200,24 @@ Future<void> migrateExistingNodesToUseAutoSwitching(
1200 'zano.cakewallet.com:11211',
1201 'electrum.cakewallet.com:50002',
1202 ];
1468 - for (var node in [...nodes.values.toList(), ...powNodes.values.toList()]) {
1203 + final nodes = await Node.getAll();
1204 + for (var node in nodes) {
1205 if (listOfDefaultNodesWithAutoSwitching.contains(node.uriRaw)) {
1206 node.isEnabledForAutoSwitching = true;
1207 await node.save();
1208 }
1209 }
1210 +
1211 + final powNodes = await Node.getAllPow();
1212 +
1213 + for(var node in powNodes) {
1214 + if (listOfDefaultNodesWithAutoSwitching.contains(node.uriRaw)) {
1215 + node.isEnabledForAutoSwitching = true;
1216 + node.isPow = true;
1217 + await node.save();
1218 + }
1219 + }
1220 +
1221 }
1222
1223 Future<void> _addXautTokenToExistingEthereumWallets() async {
lib/entities/node_check.dart new
+69
@@ -0,0 +1,69 @@
1 +import 'package:cake_wallet/core/utilities.dart';
2 +import 'package:cake_wallet/entities/preferences_key.dart';
3 +import 'package:cake_wallet/store/settings_store.dart';
4 +import 'package:cw_core/node.dart';
5 +import 'package:cw_core/node_list.dart';
6 +import 'package:cw_core/wallet_type.dart';
7 +import 'package:shared_preferences/shared_preferences.dart';
8 +
9 +const Map<WalletType, String> nodePreferenceKeys = {
10 + WalletType.monero: PreferencesKey.currentNodeIdKey,
11 + WalletType.bitcoin: PreferencesKey.currentBitcoinElectrumSererIdKey,
12 + WalletType.litecoin: PreferencesKey.currentLitecoinElectrumSererIdKey,
13 + WalletType.haven: PreferencesKey.currentHavenNodeIdKey,
14 + WalletType.ethereum: PreferencesKey.currentEthereumNodeIdKey,
15 + WalletType.polygon: PreferencesKey.currentPolygonNodeIdKey,
16 + WalletType.base: PreferencesKey.currentBaseNodeIdKey,
17 + WalletType.arbitrum: PreferencesKey.currentArbitrumNodeIdKey,
18 + WalletType.bsc: PreferencesKey.currentBscNodeIdKey,
19 + WalletType.nano: PreferencesKey.currentNanoNodeIdKey,
20 + WalletType.decred: PreferencesKey.currentDecredNodeIdKey,
21 + WalletType.bitcoinCash: PreferencesKey.currentBitcoinCashNodeIdKey,
22 + WalletType.dogecoin: PreferencesKey.currentDogecoinNodeIdKey,
23 + WalletType.solana: PreferencesKey.currentSolanaNodeIdKey,
24 + WalletType.tron: PreferencesKey.currentTronNodeIdKey,
25 + WalletType.wownero: PreferencesKey.currentWowneroNodeIdKey,
26 + WalletType.zano: PreferencesKey.currentZanoNodeIdKey,
27 + WalletType.zcash: PreferencesKey.currentZcashNodeIdKey,
28 +};
29 +
30 +const Map<WalletType, String> powNodePreferenceKeys = {
31 + WalletType.nano: PreferencesKey.currentNanoPowNodeIdKey
32 +};
33 +
34 +Future<void> checkNodeForWalletType(SharedPreferences sharedPreferences, SettingsStore settingsStore, WalletType type, bool isPow) async {
35 + final preferenceKey = isPow ? powNodePreferenceKeys[type] : nodePreferenceKeys[type];
36 +
37 + if(preferenceKey == null) {
38 + return;
39 + }
40 +
41 + final currentId = await sharedPreferences.getInt(preferenceKey);
42 +
43 + final nodes = isPow ? await Node.getAllForWalletTypePow(type) : await Node.getAllForWalletType(type);
44 + final currentNode = nodes.firstWhereOrNull((item)=>item.id == currentId);
45 +
46 + if(currentNode == null) {
47 + final newNode = (isPow
48 + ? await Node.getDefaultPowForWalletType(type)
49 + : await Node.getDefaultForWalletType(type)) ??
50 + await getDefaultNodeFromFiles(type, isPow: isPow);
51 + final newId = await newNode.save();
52 + sharedPreferences.setInt(preferenceKey, newId);
53 + settingsStore.nodes[type] = newNode;
54 + } else {
55 + settingsStore.nodes[type] = currentNode;
56 + }
57 +
58 +}
59 +
60 +
61 +Future<void> checkCurrentNodes(SharedPreferences sharedPreferences, SettingsStore settingsStore) async {
62 + for(final walletType in nodePreferenceKeys.keys) {
63 + await checkNodeForWalletType(sharedPreferences, settingsStore, walletType, false);
64 + }
65 +
66 + for(final walletType in powNodePreferenceKeys.keys) {
67 + await checkNodeForWalletType(sharedPreferences, settingsStore, walletType, true);
68 + }
69 +}
\ No newline at end of file
lib/entities/node_list.dart
-148
@@ -1,148 +0,0 @@
1 -import 'package:flutter/services.dart';
2 -import 'package:hive/hive.dart';
3 -import "package:yaml/yaml.dart";
4 -import 'package:cw_core/node.dart';
5 -import 'package:cw_core/wallet_type.dart';
6 -
7 -Future<List<Node>> loadDefaultNodes(WalletType type) async {
8 - String path;
9 - switch (type) {
10 - case WalletType.monero:
11 - path = 'assets/node_list.yml';
12 - break;
13 - case WalletType.bitcoin:
14 - path = 'assets/bitcoin_electrum_server_list.yml';
15 - break;
16 - case WalletType.litecoin:
17 - path = 'assets/litecoin_electrum_server_list.yml';
18 - break;
19 - case WalletType.haven:
20 - path = 'assets/haven_node_list.yml';
21 - break;
22 - // TODO: (refactoring) each wallet would have its path, so `wallet.nodePath` would be decided based on chain id in Evm wallet
23 - case WalletType.ethereum:
24 - path = 'assets/ethereum_server_list.yml';
25 - break;
26 - case WalletType.nano:
27 - path = 'assets/nano_node_list.yml';
28 - break;
29 - case WalletType.bitcoinCash:
30 - path = 'assets/bitcoin_cash_electrum_server_list.yml';
31 - break;
32 - case WalletType.polygon:
33 - path = 'assets/polygon_node_list.yml';
34 - break;
35 - case WalletType.solana:
36 - path = 'assets/solana_node_list.yml';
37 - break;
38 - case WalletType.tron:
39 - path = 'assets/tron_node_list.yml';
40 - break;
41 - case WalletType.wownero:
42 - path = 'assets/wownero_node_list.yml';
43 - break;
44 - case WalletType.zano:
45 - path = 'assets/zano_node_list.yml';
46 - break;
47 - case WalletType.decred:
48 - path = 'assets/decred_node_list.yml';
49 - break;
50 - case WalletType.dogecoin:
51 - path = 'assets/dogecoin_electrum_server_list.yml';
52 - break;
53 - case WalletType.base:
54 - path = 'assets/base_node_list.yml';
55 - break;
56 - case WalletType.arbitrum:
57 - path = 'assets/arbitrum_node_list.yml';
58 - break;
59 - case WalletType.zcash:
60 - path = 'assets/zcash_node_list.yml';
61 - break;
62 - case WalletType.bsc:
63 - path = 'assets/bsc_node_list.yml';
64 - break;
65 - case WalletType.banano:
66 - case WalletType.none:
67 - path = '';
68 - break;
69 - }
70 -
71 - final nodesRaw = await rootBundle.loadString(path);
72 - final loadedNodes = loadYaml(nodesRaw) as YamlList;
73 - final nodes = <Node>[];
74 -
75 - for (final raw in loadedNodes) {
76 - if (raw is Map) {
77 - final node = Node.fromMap(Map<String, Object>.from(raw));
78 - node.type = type;
79 - nodes.add(node);
80 - }
81 - }
82 -
83 - return nodes;
84 -}
85 -
86 -Future<List<Node>> loadDefaultNanoPowNodes() async {
87 - final powNodesRaw = await rootBundle.loadString('assets/nano_pow_node_list.yml');
88 - final loadedPowNodes = loadYaml(powNodesRaw) as YamlList;
89 - final nodes = <Node>[];
90 -
91 - for (final raw in loadedPowNodes) {
92 - if (raw is Map) {
93 - final node = Node.fromMap(Map<String, Object>.from(raw));
94 - node.type = WalletType.nano;
95 - nodes.add(node);
96 - }
97 - }
98 -
99 - return nodes;
100 -}
101 -
102 -Future<void> resetToDefault(Box<Node> nodeSource) async {
103 - final moneroNodes = await loadDefaultNodes(WalletType.monero);
104 - final bitcoinElectrumServerList = await loadDefaultNodes(WalletType.bitcoin);
105 - final litecoinElectrumServerList = await loadDefaultNodes(WalletType.litecoin);
106 - final bitcoinCashElectrumServerList = await loadDefaultNodes(WalletType.bitcoinCash);
107 - final havenNodes = await loadDefaultNodes(WalletType.haven);
108 - final ethereumNodes = await loadDefaultNodes(WalletType.ethereum);
109 - final nanoNodes = await loadDefaultNodes(WalletType.nano);
110 - final polygonNodes = await loadDefaultNodes(WalletType.polygon);
111 - final solanaNodes = await loadDefaultNodes(WalletType.solana);
112 - final tronNodes = await loadDefaultNodes(WalletType.tron);
113 - final decredNodes = await loadDefaultNodes(WalletType.decred);
114 - final zanoNodes = await loadDefaultNodes(WalletType.zano);
115 - final dogecoinElectrumServerList = await loadDefaultNodes(WalletType.dogecoin);
116 - final baseNodes = await loadDefaultNodes(WalletType.base);
117 - final arbitrumNodes = await loadDefaultNodes(WalletType.arbitrum);
118 - final zcashNodes = await loadDefaultNodes(WalletType.zcash);
119 - final bscNodes = await loadDefaultNodes(WalletType.bsc);
120 -
121 - final nodes = moneroNodes +
122 - bitcoinElectrumServerList +
123 - litecoinElectrumServerList +
124 - havenNodes +
125 - ethereumNodes +
126 - bitcoinCashElectrumServerList +
127 - nanoNodes +
128 - polygonNodes +
129 - solanaNodes +
130 - tronNodes +
131 - zanoNodes +
132 - decredNodes +
133 - dogecoinElectrumServerList +
134 - baseNodes +
135 - arbitrumNodes +
136 - zcashNodes +
137 - bscNodes;
138 -
139 - await nodeSource.clear();
140 - await nodeSource.addAll(nodes);
141 -}
142 -
143 -Future<void> resetPowToDefault(Box<Node> powNodeSource) async {
144 - final nanoPowNodes = await loadDefaultNanoPowNodes();
145 - final nodes = nanoPowNodes;
146 - await powNodeSource.clear();
147 - await powNodeSource.addAll(nodes);
148 -}
lib/main.dart
+7 -16
@@ -16,6 +16,7 @@ import 'package:cake_wallet/entities/default_settings_migration.dart';
16 import 'package:cake_wallet/entities/get_encryption_key.dart';
17 import 'package:cake_wallet/entities/haven_seed_store.dart';
18 import 'package:cake_wallet/entities/language_service.dart';
19 +import 'package:cake_wallet/entities/node_check.dart';
20 import 'package:cake_wallet/entities/template.dart';
21 import 'package:cake_wallet/entities/transaction_description.dart';
22 import 'package:cake_wallet/exchange/exchange_template.dart';
@@ -46,6 +47,7 @@ import 'package:cw_core/hive_type_ids.dart';
47 import 'package:cw_core/key.dart';
48 import 'package:cw_core/mweb_utxo.dart';
49 import 'package:cw_core/node.dart';
50 +import 'package:cw_core/node_legacy.dart' show performNodeHiveMigration;
51 import 'package:cw_core/payjoin_session.dart';
52 import 'package:cw_core/root_dir.dart';
53 import 'package:cw_core/spl_token.dart';
@@ -220,9 +222,6 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
222 CakeHive.registerAdapter(ContactAdapter());
223 }
224
223 - if (!CakeHive.isAdapterRegistered(Node.typeId)) {
224 - CakeHive.registerAdapter(NodeAdapter());
225 - }
225
226 if (!CakeHive.isAdapterRegistered(TransactionDescription.typeId)) {
227 CakeHive.registerAdapter(TransactionDescriptionAdapter());
@@ -286,13 +285,12 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
285 await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
286 final ordersBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Order.boxKey);
287 final contacts = await CakeHive.openBox<Contact>(Contact.boxName);
289 - final nodes = await CakeHive.openBox<Node>(Node.boxName);
290 - final powNodes =
291 - await CakeHive.openBox<Node>(Node.boxName + "pow"); // must be different from Node.boxName
288 final transactionDescriptions = await CakeHive.openBox<TransactionDescription>(
289 TransactionDescription.boxName,
290 encryptionKey: transactionDescriptionsBoxKey);
291 await performTradeHiveMigration(secureStorage);
292 + await performNodeHiveMigration();
293 + await validateBuiltinNodes();
294
295 final orders = await CakeHive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
296 final templates = await CakeHive.openBox<Template>(Template.boxName);
@@ -309,8 +307,6 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
307 await initialSetup(
308 loadWallet: loadWallet,
309 sharedPreferences: await SharedPreferences.getInstance(),
312 - nodes: nodes,
313 - powNodes: powNodes,
310 contactSource: contacts,
311 ordersSource: orders,
312 unspentCoinsInfoSource: unspentCoinsInfoSource,
@@ -322,15 +318,13 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
318 payjoinSessionSource: payjoinSessionSource,
319 anonpayInvoiceInfo: anonpayInvoiceInfo,
320 havenSeedStore: havenSeedStore,
325 - initialMigrationVersion: 65,
321 + initialMigrationVersion: 66,
322 );
323 }
324
325 Future<void> initialSetup({
326 required bool loadWallet,
327 required SharedPreferences sharedPreferences,
332 - required Box<Node> nodes,
333 - required Box<Node> powNodes,
328 required Box<Contact> contactSource,
329 required Box<Order> ordersSource,
330 // required FiatConvertationService fiatConvertationService,
@@ -350,13 +344,9 @@ Future<void> initialSetup({
344 version: initialMigrationVersion,
345 sharedPreferences: sharedPreferences,
346 contactSource: contactSource,
353 - nodes: nodes,
354 - powNodes: powNodes,
347 havenSeedStore: havenSeedStore,
348 );
349 await setup(
358 - nodeSource: nodes,
359 - powNodeSource: powNodes,
350 contactSource: contactSource,
351 ordersSource: ordersSource,
352 templates: templates,
@@ -368,11 +358,12 @@ Future<void> initialSetup({
358 navigatorKey: navigatorKey,
359 secureStorage: secureStorage,
360 );
361 + final settingsStore = getIt<SettingsStore>();
362 + await checkCurrentNodes(sharedPreferences, settingsStore);
363
364 await getIt.get<ResetService>().resetAuthDataOnNewInstall(sharedPreferences);
365
366 await bootstrapOffline();
375 - final settingsStore = getIt<SettingsStore>();
367 if (!settingsStore.currentBuiltinTor) {
368 bootstrapOnline(navigatorKey, loadWallet: loadWallet);
369 }
lib/new-ui/widgets/send_page/send_confirm_sheet.dart
+1
@@ -15,6 +15,7 @@ import 'package:cw_core/crypto_amount_format.dart';
15 import 'package:cw_core/crypto_currency.dart';
16 import 'package:flutter/material.dart';
17 import 'package:flutter_mobx/flutter_mobx.dart';
18 +import 'package:flutter_svg/flutter_svg.dart';
19 import 'package:mobx/mobx.dart';
20
21 class SendConfirmSheet extends StatefulWidget {
lib/src/screens/nodes/node_create_or_edit_page.dart
+5 -4
@@ -128,15 +128,16 @@ class _NodeCreateOrEditPageState extends State<NodeCreateOrEditPage> {
128 ),
129 ) ??
130 false;
131 -
131 +
132 if (confirmed) {
133 - await widget.editingNode!.delete();
133 + await widget.nodeCreateOrEditViewModel.delete(editingNode: widget.editingNode!);
134 Navigator.of(context).pop();
135 }
136 },
137 text: S.of(context).delete,
138 isDisabled: widget.editingNode == null ||
139 !widget.nodeCreateOrEditViewModel.isReady ||
140 + widget.editingNode!.isBuiltin ||
141 (widget.isSelected ?? false),
142 color: Theme.of(context).colorScheme.errorContainer,
143 textColor: Theme.of(context).colorScheme.onErrorContainer,
@@ -151,9 +152,9 @@ class _NodeCreateOrEditPageState extends State<NodeCreateOrEditPage> {
152 if (_nodeFormKey.currentState != null && !_nodeFormKey.currentState!.validate()) {
153 return;
154 }
154 -
155 +
156 await widget.nodeCreateOrEditViewModel.save(
156 - editingNode: widget.editingNode, saveAsCurrent: widget.isSelected ?? false);
157 + saveAsCurrent: widget.isSelected ?? false);
158 if (context.mounted) {
159 Navigator.of(context).pop();
160 }
lib/src/screens/nodes/pow_node_create_or_edit_page.dart
+1 -1
@@ -143,7 +143,7 @@ class _PowNodeCreateOrEditPageState extends State<PowNodeCreateOrEditPage> {
143 }
144
145 await widget.nodeCreateOrEditViewModel.save(
146 - editingNode: widget.editingNode, saveAsCurrent: widget.isSelected ?? false);
146 + saveAsCurrent: widget.isSelected ?? false);
147 Navigator.of(context).pop();
148 },
149 text: S.of(context).save,
lib/src/screens/nodes/widgets/node_form.dart
+64 -59
@@ -65,66 +65,77 @@ class NodeFormState extends State<NodeForm> {
65 key: _formKey,
66 child: NewListSections(
67 sections: {
68 - 'main': [
69 - ListItemTextField(
70 - keyValue: vm.nodeLabelUIKey,
71 - label: 'Node label',
72 - initialValue: vm.label,
73 - ),
74 - ListItemTextField(
75 - keyValue: vm.nodeAddressUIKey,
76 - label: S.current.node_address,
77 - initialValue: vm.address,
78 - validator: vm.walletType == WalletType.decred
79 - ? NodeAddressValidatorDecredBlankException()
80 - : NodeAddressValidator(),
81 - ),
82 - if (vm.hasPathSupport)
68 + if(!(vm.editingNode?.isBuiltin ?? false)) ...{
69 + 'main': [
70 ListItemTextField(
84 - keyValue: vm.nodePathUIKey,
85 - label: '/path',
86 - initialValue: vm.path,
87 - validator: NodePathValidator(),
71 + keyValue: vm.nodeLabelUIKey,
72 + label: 'Node label',
73 + initialValue: vm.label,
74 ),
89 - ListItemTextField(
90 - keyValue: vm.nodePortUIKey,
91 - label: S.current.node_port,
92 - initialValue: '',
93 - //keyboardType: TextInputType.numberWithOptions(signed: false, decimal: false),
94 - validator: NodePortValidator(),
95 - ),
96 - if (vm.hasAuthCredentials) ...[
75 ListItemTextField(
98 - keyValue: vm.nodeUsernameUIKey,
99 - label: S.current.login,
100 - initialValue: vm.login,
76 + keyValue: vm.nodeAddressUIKey,
77 + label: S.current.node_address,
78 + initialValue: vm.address,
79 + validator: vm.walletType == WalletType.decred
80 + ? NodeAddressValidatorDecredBlankException()
81 + : NodeAddressValidator(),
82 ),
83 + if (vm.hasPathSupport)
84 + ListItemTextField(
85 + keyValue: vm.nodePathUIKey,
86 + label: '/path',
87 + initialValue: vm.path,
88 + validator: NodePathValidator(),
89 + ),
90 ListItemTextField(
103 - keyValue: vm.nodePasswordUIKey,
104 - label: S.current.password,
105 - initialValue: vm.password,
91 + keyValue: vm.nodePortUIKey,
92 + label: S.current.node_port,
93 + initialValue: '',
94 + //keyboardType: TextInputType.numberWithOptions(signed: false, decimal: false),
95 + validator: NodePortValidator(),
96 ),
107 - ]
108 - ],
109 - 'advanced': [
110 - ListItemCheckbox(
111 - keyValue: vm.useSSLUIKey,
112 - label: S.current.use_ssl,
113 - value: vm.useSSL,
114 - onChanged: (value) => vm.useSSL = value),
115 - ListItemCheckbox(
116 - keyValue: vm.nodeTrustedUIKey,
117 - label: S.current.trusted,
118 - value: vm.trusted,
119 - onChanged: (value) => vm.trusted = value,
120 - ),
121 - if (vm.usesEmbeddedProxy)
97 + if (vm.hasAuthCredentials) ...[
98 + ListItemTextField(
99 + keyValue: vm.nodeUsernameUIKey,
100 + label: S.current.login,
101 + initialValue: vm.login,
102 + ),
103 + ListItemTextField(
104 + keyValue: vm.nodePasswordUIKey,
105 + label: S.current.password,
106 + initialValue: vm.password,
107 + ),
108 + ]
109 + ],
110 + 'advanced': [
111 ListItemCheckbox(
123 - keyValue: vm.nodeEmbeddedTorProxyUIKey,
124 - label: 'Embedded Tor SOCKS Proxy',
125 - value: vm.usesEmbeddedProxy,
126 - onChanged: (_) {},
112 + keyValue: vm.useSSLUIKey,
113 + label: S.current.use_ssl,
114 + value: vm.useSSL,
115 + onChanged: (value) => vm.useSSL = value),
116 + ListItemCheckbox(
117 + keyValue: vm.nodeTrustedUIKey,
118 + label: S.current.trusted,
119 + value: vm.trusted,
120 + onChanged: (value) => vm.trusted = value,
121 ),
122 + if (vm.usesEmbeddedProxy)
123 + ListItemCheckbox(
124 + keyValue: vm.nodeEmbeddedTorProxyUIKey,
125 + label: 'Embedded Tor SOCKS Proxy',
126 + value: vm.usesEmbeddedProxy,
127 + onChanged: (_) {},
128 + ),
129 + if(FeatureFlag.isAutomaticNodeSwitchingEnabled)
130 + ListItemCheckbox(
131 + keyValue: vm.autoSwitchingUIKey,
132 + label: S.current.enable_for_auto_switching,
133 + value: vm.isEnabledForAutoSwitching,
134 + onChanged: (value) => vm.isEnabledForAutoSwitching = value),
135 + ],
136 + },
137 +
138 + "proxy" : [
139 ListItemCheckbox(
140 keyValue: vm.useSocksProxyUIKey,
141 label: 'Use SOCKS Proxy',
@@ -141,13 +152,7 @@ class NodeFormState extends State<NodeForm> {
152 initialValue: vm.socksProxyAddress,
153 validator: SocksProxyNodeAddressValidator(),
154 ),
144 - if(FeatureFlag.isAutomaticNodeSwitchingEnabled)
145 - ListItemCheckbox(
146 - keyValue: vm.autoSwitchingUIKey,
147 - label: S.current.enable_for_auto_switching,
148 - value: vm.isEnabledForAutoSwitching,
149 - onChanged: (value) => vm.isEnabledForAutoSwitching = value),
150 - ],
155 + ]
156 },
157 controllers: _controllers,
158 getCheckboxValue: vm.getCheckboxValue,
lib/src/screens/settings/manage_nodes_page.dart
+2 -2
@@ -94,9 +94,9 @@ class ManageNodesPage extends BasePage {
94 nodeListViewModel?.nodes[index] ?? powNodeListViewModel!.nodes[index];
95 late bool isSelected;
96 if (isPow) {
97 - isSelected = node.keyIndex == powNodeListViewModel!.currentNode.keyIndex;
97 + isSelected = node.id == powNodeListViewModel!.currentNode.id;
98 } else {
99 - isSelected = node.keyIndex == nodeListViewModel!.currentNode.keyIndex;
99 + isSelected = node.id == nodeListViewModel!.currentNode.id;
100 }
101 final nodeListRow = NodeListRow(
102 title: node.uriRaw,
lib/store/app_store.dart
-3
@@ -14,7 +14,6 @@ import 'package:cw_core/transaction_history.dart';
14 import 'package:cake_wallet/store/wallet_list_store.dart';
15 import 'package:cake_wallet/store/authentication_store.dart';
16 import 'package:cake_wallet/store/settings_store.dart';
17 -import 'package:cake_wallet/store/node_list_store.dart';
17 import 'package:shared_preferences/shared_preferences.dart';
18
19 part 'app_store.g.dart';
@@ -26,7 +25,6 @@ abstract class AppStoreBase with Store {
25 required this.authenticationStore,
26 required this.walletList,
27 required this.settingsStore,
29 - required this.nodeListStore,
28 required this.themeStore,
29 }) : _amountParsingProxy = AmountParsingProxy(settingsStore.displayAmountsInSatoshi) {
30 reaction(
@@ -47,7 +45,6 @@ abstract class AppStoreBase with Store {
45
46 SettingsStore settingsStore;
47
50 - NodeListStore nodeListStore;
48
49 ThemeStore themeStore;
50
lib/store/node_list_store.dart
-34
@@ -1,34 +0,0 @@
1 -import 'dart:async';
2 -import 'package:hive/hive.dart';
3 -import 'package:mobx/mobx.dart';
4 -import 'package:cake_wallet/di.dart';
5 -import 'package:cw_core/node.dart';
6 -import 'package:cake_wallet/utils/mobx.dart';
7 -
8 -part 'node_list_store.g.dart';
9 -
10 -class NodeListStore = NodeListStoreBase with _$NodeListStore;
11 -
12 -abstract class NodeListStoreBase with Store {
13 - NodeListStoreBase() : nodes = ObservableList<Node>();
14 -
15 - static StreamSubscription<BoxEvent>? _onNodesSourceChange;
16 - static NodeListStore? _instance;
17 -
18 - static NodeListStore get instance {
19 - if (_instance != null) {
20 - return _instance!;
21 - }
22 -
23 - final nodeSource = getIt.get<Box<Node>>();
24 - _instance = NodeListStore();
25 - _instance!.nodes.clear();
26 - _instance!.nodes.addAll(nodeSource.values);
27 - _onNodesSourceChange?.cancel();
28 - _onNodesSourceChange = nodeSource.bindToList(_instance!.nodes);
29 -
30 - return _instance!;
31 - }
32 -
33 - final ObservableList<Node> nodes;
34 -}
lib/store/settings_store.dart
+78 -55
@@ -995,7 +995,7 @@ abstract class SettingsStoreBase with Store {
995
996 @observable
997 bool mwebCardDisplay;
998 -
998 +
999 @observable
1000 bool showZcashMissingFundsCard;
1001
@@ -1104,8 +1104,7 @@ abstract class SettingsStoreBase with Store {
1104 _sharedPreferences.setBool(PreferencesKey.shouldShowReceiveWarning, value);
1105
1106 static Future<SettingsStore> load(
1107 - {required Box<Node> nodeSource,
1108 - required Box<Node> powNodeSource,
1107 + {
1108 required bool isBitcoinBuyEnabled,
1109 FiatCurrency initialFiatCurrency = FiatCurrency.usd,
1110 BalanceDisplayMode initialBalanceDisplayMode = BalanceDisplayMode.availableBalance}) async {
@@ -1318,43 +1317,66 @@ abstract class SettingsStoreBase with Store {
1317 final decredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
1318 final dogecoinNodeId = sharedPreferences.getInt(PreferencesKey.currentDogecoinNodeIdKey);
1319
1320 +
1321 + final nodeSource = await Node.getAll();
1322 + final powNodeSource = await Node.getAllPow();
1323 +
1324 /// get the selected node, if null, then use the default
1322 - final moneroNode = nodeSource.get(nodeId) ??
1323 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == newCakeWalletMoneroUri);
1324 - final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId) ??
1325 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == newCakeWalletBitcoinUri);
1326 - final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId) ??
1327 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == cakeWalletLitecoinElectrumUri);
1328 - final ethereumNode = nodeSource.get(ethereumNodeId) ??
1329 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == ethereumDefaultNodeUri);
1330 - final polygonNode = nodeSource.get(polygonNodeId) ??
1331 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == polygonDefaultNodeUri);
1332 - final baseNode = nodeSource.get(baseNodeId) ??
1333 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == baseDefaultNodeUri);
1334 - final arbitrumNode = nodeSource.get(arbitrumNodeId) ??
1335 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == arbitrumDefaultNodeUri);
1336 - final bscNode = nodeSource.get(bscNodeId) ??
1337 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == bscDefaultNodeUri);
1338 - final bitcoinCashElectrumServer = nodeSource.get(bitcoinCashElectrumServerId) ??
1339 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == cakeWalletBitcoinCashDefaultNodeUri);
1340 - final nanoNode = nodeSource.get(nanoNodeId) ??
1341 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == nanoDefaultNodeUri);
1342 - final decredNode = nodeSource.get(decredNodeId) ??
1343 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == decredDefaultUri);
1344 - final nanoPowNode = powNodeSource.get(nanoPowNodeId) ??
1345 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == nanoDefaultPowNodeUri);
1346 - final solanaNode = nodeSource.get(solanaNodeId) ??
1347 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == solanaDefaultNodeUri);
1348 - final tronNode = nodeSource.get(tronNodeId) ??
1349 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == tronDefaultNodeUri);
1350 - final wowneroNode = nodeSource.get(wowneroNodeId) ??
1351 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == wowneroDefaultNodeUri);
1352 - final zanoNode = nodeSource.get(zanoNodeId) ??
1353 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == zanoDefaultNodeUri);
1354 - final zcashNode = nodeSource.get(zcashNodeId) ??
1355 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == zcashDefaultNodeUri);
1356 - final dogecoinNode = nodeSource.get(dogecoinNodeId) ??
1357 - nodeSource.values.firstWhereOrNull((e) => e.uriRaw == dogecoinDefaultNodeUri);
1325 + final moneroNode = nodeSource.firstWhereOrNull((e) => e.id == nodeId) ??
1326 + nodeSource.firstWhereOrNull((e) => e.uriRaw == newCakeWalletMoneroUri);
1327 + final bitcoinElectrumServer =
1328 + nodeSource.firstWhereOrNull((e) => e.id == bitcoinElectrumServerId) ??
1329 + nodeSource.firstWhereOrNull((e) => e.uriRaw == newCakeWalletBitcoinUri);
1330 + final litecoinElectrumServer =
1331 + nodeSource.firstWhereOrNull((e) => e.id == litecoinElectrumServerId) ??
1332 + nodeSource.firstWhereOrNull((e) => e.uriRaw == cakeWalletLitecoinElectrumUri);
1333 + final ethereumNode =
1334 + nodeSource.firstWhereOrNull((e) => e.id == ethereumNodeId) ??
1335 + nodeSource.firstWhereOrNull((e) => e.uriRaw == ethereumDefaultNodeUri);
1336 + final polygonNode =
1337 + nodeSource.firstWhereOrNull((e) => e.id == polygonNodeId) ??
1338 + nodeSource.firstWhereOrNull((e) => e.uriRaw == polygonDefaultNodeUri);
1339 + final baseNode =
1340 + nodeSource.firstWhereOrNull((e) => e.id == baseNodeId) ??
1341 + nodeSource.firstWhereOrNull((e) => e.uriRaw == baseDefaultNodeUri);
1342 + final arbitrumNode =
1343 + nodeSource.firstWhereOrNull((e) => e.id == arbitrumNodeId) ??
1344 + nodeSource.firstWhereOrNull((e) => e.uriRaw == arbitrumDefaultNodeUri);
1345 + final bitcoinCashElectrumServer =
1346 + nodeSource.firstWhereOrNull((e) => e.id == bitcoinCashElectrumServerId) ??
1347 + nodeSource.firstWhereOrNull(
1348 + (e) => e.uriRaw == cakeWalletBitcoinCashDefaultNodeUri);
1349 + final nanoNode =
1350 + nodeSource.firstWhereOrNull((e) => e.id == nanoNodeId) ??
1351 + nodeSource.firstWhereOrNull((e) => e.uriRaw == nanoDefaultNodeUri);
1352 + final decredNode =
1353 + nodeSource.firstWhereOrNull((e) => e.id == decredNodeId) ??
1354 + nodeSource.firstWhereOrNull((e) => e.uriRaw == decredDefaultUri);
1355 + final nanoPowNode =
1356 + powNodeSource.firstWhereOrNull((e) => e.id == nanoPowNodeId) ??
1357 + powNodeSource.firstWhereOrNull(
1358 + (e) => e.uriRaw == nanoDefaultPowNodeUri);
1359 + final solanaNode =
1360 + nodeSource.firstWhereOrNull((e) => e.id == solanaNodeId) ??
1361 + nodeSource.firstWhereOrNull((e) => e.uriRaw == solanaDefaultNodeUri);
1362 + final tronNode =
1363 + nodeSource.firstWhereOrNull((e) => e.id == tronNodeId) ??
1364 + nodeSource.firstWhereOrNull((e) => e.uriRaw == tronDefaultNodeUri);
1365 + final wowneroNode =
1366 + nodeSource.firstWhereOrNull((e) => e.id == wowneroNodeId) ??
1367 + nodeSource.firstWhereOrNull((e) => e.uriRaw == wowneroDefaultNodeUri);
1368 + final zanoNode =
1369 + nodeSource.firstWhereOrNull((e) => e.id == zanoNodeId) ??
1370 + nodeSource.firstWhereOrNull((e) => e.uriRaw == zanoDefaultNodeUri);
1371 + final dogecoinNode =
1372 + nodeSource.firstWhereOrNull((e) => e.id == dogecoinNodeId) ??
1373 + nodeSource.firstWhereOrNull((e) => e.uriRaw == dogecoinDefaultNodeUri);
1374 + final zcashNode =
1375 + nodeSource.firstWhereOrNull((e) => e.id == zcashNodeId) ??
1376 + nodeSource.firstWhereOrNull((e) => e.uriRaw == zcashDefaultNodeUri);
1377 + final bscNode =
1378 + nodeSource.firstWhereOrNull((e) => e.id == bscNodeId) ??
1379 + nodeSource.firstWhereOrNull((e) => e.uriRaw == bscDefaultNodeUri);
1380
1381 final packageInfo = await PackageInfo.fromPlatform();
1382 final deviceName = await _getDeviceName() ?? '';
@@ -1572,7 +1594,7 @@ abstract class SettingsStoreBase with Store {
1594
1595 final mwebAdDismissed =
1596 await sharedPreferences.getBool(PreferencesKey.mwebAdDismissed) ?? false;
1575 -
1597 +
1598 final balanceHideCounter = await sharedPreferences.getInt(PreferencesKey.balanceHideCounter) ?? 0;
1599
1600 return SettingsStore(
@@ -2085,20 +2107,21 @@ abstract class SettingsStoreBase with Store {
2107 }
2108
2109 Future<void> _saveCurrentNode(Node node, WalletType walletType) async {
2110 +
2111 switch (walletType) {
2112 case WalletType.bitcoin:
2113 await _sharedPreferences.setInt(
2091 - PreferencesKey.currentBitcoinElectrumSererIdKey, node.key as int);
2114 + PreferencesKey.currentBitcoinElectrumSererIdKey, node.id);
2115 break;
2116 case WalletType.litecoin:
2117 await _sharedPreferences.setInt(
2095 - PreferencesKey.currentLitecoinElectrumSererIdKey, node.key as int);
2118 + PreferencesKey.currentLitecoinElectrumSererIdKey, node.id);
2119 break;
2120 case WalletType.monero:
2098 - await _sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, node.key as int);
2121 + await _sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, node.id);
2122 break;
2123 case WalletType.haven:
2101 - await _sharedPreferences.setInt(PreferencesKey.currentHavenNodeIdKey, node.key as int);
2124 + await _sharedPreferences.setInt(PreferencesKey.currentHavenNodeIdKey, node.id);
2125 break;
2126 case WalletType.ethereum:
2127 case WalletType.polygon:
@@ -2107,36 +2130,36 @@ abstract class SettingsStoreBase with Store {
2130 case WalletType.bsc:
2131 final chainId = evm!.getChainIdByWalletType(node.type);
2132 final preferenceKey = _getEVMNodePreferenceKey(chainId);
2110 - await _sharedPreferences.setInt(preferenceKey, node.key as int);
2133 + await _sharedPreferences.setInt(preferenceKey, node.id);
2134 nodes[node.type] = node;
2135 break;
2136 case WalletType.bitcoinCash:
2137 await _sharedPreferences.setInt(
2115 - PreferencesKey.currentBitcoinCashNodeIdKey, node.key as int);
2138 + PreferencesKey.currentBitcoinCashNodeIdKey, node.id);
2139 break;
2140 case WalletType.nano:
2118 - await _sharedPreferences.setInt(PreferencesKey.currentNanoNodeIdKey, node.key as int);
2141 + await _sharedPreferences.setInt(PreferencesKey.currentNanoNodeIdKey, node.id);
2142 break;
2143 case WalletType.solana:
2121 - await _sharedPreferences.setInt(PreferencesKey.currentSolanaNodeIdKey, node.key as int);
2144 + await _sharedPreferences.setInt(PreferencesKey.currentSolanaNodeIdKey, node.id);
2145 break;
2146 case WalletType.tron:
2124 - await _sharedPreferences.setInt(PreferencesKey.currentTronNodeIdKey, node.key as int);
2147 + await _sharedPreferences.setInt(PreferencesKey.currentTronNodeIdKey, node.id);
2148 break;
2149 case WalletType.wownero:
2127 - await _sharedPreferences.setInt(PreferencesKey.currentWowneroNodeIdKey, node.key as int);
2150 + await _sharedPreferences.setInt(PreferencesKey.currentWowneroNodeIdKey, node.id);
2151 break;
2152 case WalletType.decred:
2130 - await _sharedPreferences.setInt(PreferencesKey.currentDecredNodeIdKey, node.key as int);
2153 + await _sharedPreferences.setInt(PreferencesKey.currentDecredNodeIdKey, node.id);
2154 break;
2155 case WalletType.zano:
2133 - await _sharedPreferences.setInt(PreferencesKey.currentZanoNodeIdKey, node.key as int);
2156 + await _sharedPreferences.setInt(PreferencesKey.currentZanoNodeIdKey, node.id);
2157 break;
2158 case WalletType.dogecoin:
2136 - await _sharedPreferences.setInt(PreferencesKey.currentDogecoinNodeIdKey, node.key as int);
2159 + await _sharedPreferences.setInt(PreferencesKey.currentDogecoinNodeIdKey, node.id);
2160 break;
2161 case WalletType.zcash:
2139 - await _sharedPreferences.setInt(PreferencesKey.currentZcashNodeIdKey, node.key as int);
2162 + await _sharedPreferences.setInt(PreferencesKey.currentZcashNodeIdKey, node.id);
2163 break;
2164 case WalletType.none:
2165 throw UnimplementedError();
@@ -2150,7 +2173,7 @@ abstract class SettingsStoreBase with Store {
2173 Future<void> _saveCurrentPowNode(Node node, WalletType walletType) async {
2174 switch (walletType) {
2175 case WalletType.nano:
2153 - await _sharedPreferences.setInt(PreferencesKey.currentNanoPowNodeIdKey, node.key as int);
2176 + await _sharedPreferences.setInt(PreferencesKey.currentNanoPowNodeIdKey, node.id);
2177 break;
2178 default:
2179 break;
lib/utils/exception_handler.dart
+8 -13
@@ -117,7 +117,7 @@ class ExceptionHandler {
117 if (await onLedgerError(errorDetails)) return;
118
119 if (kDebugMode || kProfileMode) {
120 - if (_ignoreError(errorDetails.exception.toString()) ||
120 + if(_ignoreError(errorDetails.exception.toString()) ||
121 _ignoreError(errorDetails.stack.toString())) {
122 printV("(BELOW ERROR IS IGNORED AND WILL NOT TRIGGER POPUP IN PROD)");
123 }
@@ -127,8 +127,7 @@ class ExceptionHandler {
127 }
128
129 if (_ignoreError(errorDetails.exception.toString()) ||
130 - _ignoreError(errorDetails.stack.toString()) ||
131 - _flutterErrorIgnore(errorDetails)) {
130 + _ignoreError(errorDetails.stack.toString())) {
131 return;
132 }
133
@@ -216,7 +215,8 @@ class ExceptionHandler {
215 return S.current.ledger_error_tx_rejected_by_user;
216 } else if (errorCode.contains("5515")) {
217 return S.current.ledger_error_device_locked;
219 - } else if (["6e01", "6d02", "6511", "6e00"].any((e) => errorCode.contains(e))) {
218 + } else
219 + if (["6e01", "6d02", "6511", "6e00"].any((e) => errorCode.contains(e))) {
220 return S.current.ledger_error_wrong_app;
221 }
222 return null;
@@ -229,8 +229,9 @@ class ExceptionHandler {
229 context: navigatorKey.currentContext!,
230 builder: (context) => AlertWithOneAction(
231 alertTitle: "Ledger Error",
232 - alertContent: interpretErrorCode(errorDetails.exception.toString()) ??
233 - S.of(context).ledger_connection_error,
232 + alertContent:
233 + interpretErrorCode(errorDetails.exception.toString()) ??
234 + S.of(context).ledger_connection_error,
235 buttonText: S.of(context).close,
236 buttonAction: () => Navigator.of(context).pop(),
237 ),
@@ -295,7 +296,7 @@ class ExceptionHandler {
296 "Wallet is null",
297 "Wrong Device Status: 0x5515 (UNKNOWN)",
298 "Command handling failed. With error: hostUnreachable",
298 -
299 +
300 "FocusScopeNode was used after being disposed",
301 "_getDismissibleFlushbar",
302 "_QueuedFuture.execute (package:universal_ble/src/queue.dart:65)",
@@ -438,10 +439,4 @@ class ExceptionHandler {
439
440 _hasError = false;
441 }
441 -
442 - static bool _flutterErrorIgnore(FlutterErrorDetails errorDetails) {
443 - // most probably a flutter context error so just ignore it if there is no stack we can debug with
444 - return errorDetails.exception.toString().contains("Null check operator used on a null value") &&
445 - errorDetails.stack == null;
446 - }
442 }
lib/view_model/node_list/node_create_or_edit_view_model.dart
+46 -36
@@ -5,10 +5,11 @@ import 'package:cake_wallet/store/settings_store.dart';
5 import 'package:cake_wallet/utils/permission_handler.dart';
6 import 'package:collection/collection.dart';
7 import 'package:cw_core/node.dart';
8 +import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
9 +import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
10 import 'package:cw_core/utils/proxy_wrapper.dart';
11 import 'package:cw_core/wallet_type.dart';
12 import 'package:flutter/cupertino.dart';
11 -import 'package:hive/hive.dart';
13 import 'package:mobx/mobx.dart';
14 import 'package:permission_handler/permission_handler.dart';
15
@@ -19,7 +20,7 @@ class NodeCreateOrEditViewModel = NodeCreateOrEditViewModelBase
20
21 abstract class NodeCreateOrEditViewModelBase with Store {
22 NodeCreateOrEditViewModelBase(
22 - this._nodeSource, this.walletType, this.editingNode, this._settingsStore)
23 + this.isPow, this.nodeListViewModel,this.powNodeListViewModel, this.walletType, this._settingsStore, {this.editingNode})
24 : state = InitialExecutionState(),
25 connectionState = InitialExecutionState(),
26 label = editingNode?.label ?? '',
@@ -36,8 +37,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
37 editingNode?.isEnabledForAutoSwitching ?? false,
38 useSocksProxy = editingNode?.socksProxyAddress != null &&
39 editingNode!.socksProxyAddress!.isNotEmpty,
39 - useSSL = editingNode?.useSSL ?? false {
40 - }
40 + useSSL = editingNode?.useSSL ?? false {}
41
42 final nodeLabelUIKey = 'node_label_row_key';
43 final nodeAddressUIKey = 'node_address_row_key';
@@ -110,6 +110,15 @@ abstract class NodeCreateOrEditViewModelBase with Store {
110 @observable
111 String socksProxyAddress;
112
113 + @observable
114 + Node? editingNode;
115 +
116 + @observable
117 + bool isPow;
118 +
119 + final NodeListViewModel? nodeListViewModel;
120 + final PowNodeListViewModel? powNodeListViewModel;
121 +
122 @computed
123 bool get isReady =>
124 (address.isNotEmpty) ||
@@ -158,8 +167,6 @@ abstract class NodeCreateOrEditViewModelBase with Store {
167 }
168
169 final WalletType walletType;
161 - final Node? editingNode;
162 - final Box<Node> _nodeSource;
170 final SettingsStore _settingsStore;
171
172 void updateViewModelFromText(String key, String value) {
@@ -248,33 +255,45 @@ abstract class NodeCreateOrEditViewModelBase with Store {
255 void setSocksProxyAddress(String val) => socksProxyAddress = val;
256
257 @action
251 - Future<void> save({Node? editingNode, bool saveAsCurrent = false}) async {
252 - final node = Node(
253 - label: label,
254 - uri: uri,
255 - path: path,
256 - type: walletType,
257 - login: login,
258 - password: password,
259 - useSSL: useSSL,
260 - trusted: trusted,
261 - isEnabledForAutoSwitching: isEnabledForAutoSwitching,
262 - socksProxyAddress: socksProxyAddress);
258 + Future<void> delete({required Node editingNode}) async {
259 + await editingNode.delete();
260 + if(nodeListViewModel != null) {
261 + nodeListViewModel!.bindNodes();
262 + }
263 + if(powNodeListViewModel != null) {
264 + powNodeListViewModel!.bindNodes();
265 + }
266 + }
267 +
268 + @action
269 + Future<void> save({bool saveAsCurrent = false}) async {
270 + editingNode ??= Node();
271 + editingNode!.type = walletType;
272 + editingNode!.label = label;
273 + editingNode!.uriRaw = uri;
274 + editingNode!.path = path;
275 + editingNode!.login = login;
276 + editingNode!.password = password;
277 + editingNode!.isPow = isPow;
278 + editingNode!.useSSL = useSSL;
279 + editingNode!.trusted = trusted;
280 + editingNode!.socksProxyAddress = socksProxyAddress;
281 +
282 try {
283 state = IsExecutingState();
265 - if (editingNode != null) {
266 - await _nodeSource.put(editingNode.key, node);
267 - } else if (_existingNode(node) != null) {
268 - setAsCurrent(_existingNode(node)!);
269 - } else {
270 - await _nodeSource.add(node);
271 - setAsCurrent(_nodeSource.values.last);
272 - }
284 + await editingNode!.save();
285 if (saveAsCurrent) {
274 - setAsCurrent(node);
286 + setAsCurrent(editingNode!);
287 }
288
289 state = ExecutedSuccessfullyState();
290 + if(nodeListViewModel != null) {
291 + nodeListViewModel!.bindNodes();
292 + }
293 + if(powNodeListViewModel != null) {
294 + powNodeListViewModel!.bindNodes();
295 + }
296 +
297 } catch (e) {
298 state = FailureState(e.toString());
299 }
@@ -301,15 +320,6 @@ abstract class NodeCreateOrEditViewModelBase with Store {
320 }
321 }
322
304 - Node? _existingNode(Node node) {
305 - final nodes = _nodeSource.values.toList();
306 - nodes.forEach((item) {
307 - item.login ??= '';
308 - item.password ??= '';
309 - item.useSSL ??= false;
310 - });
311 - return nodes.firstWhereOrNull((item) => item == node);
312 - }
323
324 @action
325 void setAsCurrent(Node node) => _settingsStore.nodes[walletType] = node;
lib/view_model/node_list/node_list_view_model.dart
+15 -22
@@ -1,8 +1,7 @@
1 import 'package:cake_wallet/generated/i18n.dart';
2 import 'package:cake_wallet/store/app_store.dart';
3 -import 'package:cake_wallet/utils/mobx.dart';
3 +import 'package:cw_core/node_list.dart';
4 import 'package:cw_core/utils/proxy_wrapper.dart';
5 -import 'package:hive/hive.dart';
5 import 'package:mobx/mobx.dart';
6 import 'package:cw_core/wallet_base.dart';
7 import 'package:cake_wallet/store/settings_store.dart';
@@ -18,13 +17,13 @@ part 'node_list_view_model.g.dart';
17 class NodeListViewModel = NodeListViewModelBase with _$NodeListViewModel;
18
19 abstract class NodeListViewModelBase with Store {
21 - NodeListViewModelBase(this._nodeSource, this._appStore)
20 + NodeListViewModelBase(this._appStore)
21 : nodes = ObservableList<Node>(),
22 settingsStore = _appStore.settingsStore {
24 - _bindNodes();
23 + bindNodes();
24
25 reaction((_) => _appStore.wallet, (WalletBase? _wallet) {
27 - _bindNodes();
26 + bindNodes();
27 });
28
29 reaction((_) {
@@ -35,7 +34,7 @@ abstract class NodeListViewModelBase with Store {
34 }
35 return null;
36 }, (_) {
38 - _bindNodes();
37 + bindNodes();
38 });
39 }
40
@@ -73,24 +72,24 @@ abstract class NodeListViewModelBase with Store {
72
73 final ObservableList<Node> nodes;
74 final SettingsStore settingsStore;
76 - final Box<Node> _nodeSource;
75 final AppStore _appStore;
76
77 Future<void> reset() async {
80 - await resetToDefault(_nodeSource);
78 + await resetToDefault();
79
80 final wallet = _appStore.wallet!;
81 final walletType = wallet.type;
82
83 Node node;
84 if (walletType == WalletType.bitcoin && wallet.isTestnet) {
87 - node = getBitcoinTestnetDefaultElectrumServer(nodes: _nodeSource)!;
85 + node = (await getBitcoinTestnetDefaultElectrumServer())!;
86 +
87 } else if (isEVMCompatibleChain(walletType)) {
88 final chainId = evm!.getSelectedChainId(wallet);
89 if (chainId != null) {
90 final nodeWalletType = evm!.getWalletTypeByChainId(chainId);
91 if (nodeWalletType != null) {
93 - node = getDefaultNode(nodes: _nodeSource, type: nodeWalletType)!;
92 + node = (await Node.getDefaultForWalletType(nodeWalletType))!;
93 } else {
94 throw Exception(
95 'Cannot reset node for EVM wallet: wallet type not found for chainId: $chainId');
@@ -99,7 +98,7 @@ abstract class NodeListViewModelBase with Store {
98 throw Exception('Cannot reset node for EVM wallet: chainId is null');
99 }
100 } else {
102 - node = getDefaultNode(nodes: _nodeSource, type: walletType)!;
101 + node = (await Node.getDefaultForWalletType(_appStore.wallet!.type))!;
102 }
103
104 await setAsCurrent(node);
@@ -130,7 +129,7 @@ abstract class NodeListViewModelBase with Store {
129 }
130
131 @action
133 - void _bindNodes() {
132 + Future<void> bindNodes() async {
133 nodes.clear();
134 final wallet = _appStore.wallet!;
135 final walletType = wallet.type;
@@ -141,11 +140,8 @@ abstract class NodeListViewModelBase with Store {
140 if (chainId != null) {
141 final nodeWalletType = evm!.getWalletTypeByChainId(chainId);
142 if (nodeWalletType != null) {
144 - _nodeSource.bindToList(
145 - nodes,
146 - filter: (val) => val.type == nodeWalletType,
147 - initialFire: true,
148 - );
143 + nodes.addAll(await Node.getAllForWalletType(nodeWalletType));
144 +
145 return;
146 }
147 }
@@ -154,10 +150,7 @@ abstract class NodeListViewModelBase with Store {
150 }
151
152 // For non-EVM wallets, use the wallet type directly
157 - _nodeSource.bindToList(
158 - nodes,
159 - filter: (val) => val.type == walletType,
160 - initialFire: true,
161 - );
153 + nodes.addAll(await Node.getAllForWalletType(walletType));
154 +
155 }
156 }
lib/view_model/node_list/pow_node_list_view_model.dart
+8 -12
@@ -1,6 +1,7 @@
1 import 'package:cake_wallet/generated/i18n.dart';
2 import 'package:cake_wallet/store/app_store.dart';
3 import 'package:cake_wallet/utils/mobx.dart';
4 +import 'package:cw_core/node_list.dart';
5 import 'package:cw_core/utils/proxy_wrapper.dart';
6 import 'package:hive/hive.dart';
7 import 'package:mobx/mobx.dart';
@@ -16,13 +17,13 @@ part 'pow_node_list_view_model.g.dart';
17 class PowNodeListViewModel = PowNodeListViewModelBase with _$PowNodeListViewModel;
18
19 abstract class PowNodeListViewModelBase with Store {
19 - PowNodeListViewModelBase(this._nodeSource, this._appStore)
20 + PowNodeListViewModelBase(this._appStore)
21 : nodes = ObservableList<Node>(),
22 settingsStore = _appStore.settingsStore {
22 - _bindNodes();
23 + bindNodes();
24
25 reaction((_) => _appStore.wallet, (WalletBase? _wallet) {
25 - _bindNodes();
26 + bindNodes();
27 });
28 }
29
@@ -50,17 +51,16 @@ abstract class PowNodeListViewModelBase with Store {
51
52 final ObservableList<Node> nodes;
53 final SettingsStore settingsStore;
53 - final Box<Node> _nodeSource;
54 final AppStore _appStore;
55
56 Future<void> reset() async {
57 - await resetPowToDefault(_nodeSource);
57 + await resetPowToDefault();
58
59 Node node;
60
61 switch (_appStore.wallet!.type) {
62 case WalletType.nano:
63 - node = getNanoDefaultPowNode(nodes: _nodeSource)!;
63 + node = (await getNanoDefaultPowNode())!;
64 break;
65 default:
66 throw Exception('Unexpected wallet type: ${_appStore.wallet!.type} for pow node list');
@@ -76,12 +76,8 @@ abstract class PowNodeListViewModelBase with Store {
76 settingsStore.powNodes[_appStore.wallet!.type] = node;
77
78 @action
79 - void _bindNodes() {
79 + Future<void> bindNodes() async {
80 nodes.clear();
81 - _nodeSource.bindToList(
82 - nodes,
83 - filter: (val) => val.type == _appStore.wallet!.type,
84 - initialFire: true,
85 - );
81 + nodes.addAll(await Node.getAllPow());
82 }
83 }
lib/view_model/restore_from_backup_view_model.dart
+1 -1
@@ -62,7 +62,7 @@ abstract class RestoreFromBackupViewModelBase with Store {
62
63 final store = getIt.get<AppStore>();
64 ReactionDisposer? reaction;
65 - await store.settingsStore.reload(nodeSource: getIt.get<Box<Node>>());
65 + //await store.settingsStore.reload(nodeSource: getIt.get<Box<Node>>());
66 await store.themeStore.loadSavedTheme(isFromBackup: true);
67 reaction = autorun((_) {
68 final wallet = store.wallet;
res/values/strings_ar.arb
+1 -1
@@ -1377,4 +1377,4 @@
1377 "zcash_card_missing_funds": "هل أموالك مفقودة؟",
1378 "zcash_card_scan": "مسح",
1379 "zcash_card_warning": "لا تُغلق التطبيق حتى يكتمل الإجراء، لأنك إن فعلت ذلك فستحتاج هذه العملية إلى البدء من جديد من البداية."
1380 -}
\ No newline at end of file
1380 +}
res/values/strings_bg.arb
+1 -1
@@ -1377,4 +1377,4 @@
1377 "zcash_card_missing_funds": "Липсват средства?",
1378 "zcash_card_scan": "Сканирай",
1379 "zcash_card_warning": "Не затваряйте приложението, докато процедурата не приключи. Ако го направите, процесът ще трябва да започне отначало."
1380 -}
\ No newline at end of file
1380 +}
res/values/strings_cs.arb
+1 -1
@@ -1377,4 +1377,4 @@
1377 "zcash_card_missing_funds": "Chybějící prostředky?",
1378 "zcash_card_scan": "Skenovat",
1379 "zcash_card_warning": "Nezavírejte aplikaci, dokud se postup nedokončí. Pokud tak učiníte, bude nutné tento proces spustit znovu od začátku."
1380 -}
\ No newline at end of file
1380 +}
res/values/strings_de.arb
+1 -1
@@ -1381,4 +1381,4 @@
1381 "zcash_card_missing_funds": "Fehlende Gelder?",
1382 "zcash_card_scan": "Scannen",
1383 "zcash_card_warning": "Schließen Sie die App nicht, bis der Vorgang abgeschlossen ist. Andernfalls muss der Vorgang von Grund auf neu gestartet werden."
1384 -}
\ No newline at end of file
1384 +}
res/values/strings_es.arb
+1 -1
@@ -1379,4 +1379,4 @@
1379 "zcash_card_missing_funds": "¿Faltan fondos?",
1380 "zcash_card_scan": "Escanear",
1381 "zcash_card_warning": "No cierre la aplicación hasta que se complete el procedimiento; si lo hace, este proceso deberá reiniciarse desde cero."
1382 -}
\ No newline at end of file
1382 +}
res/values/strings_fa.arb
+1 -1
@@ -1374,4 +1374,4 @@
1374 "zcash_card_missing_funds": "موجودی گم شده؟",
1375 "zcash_card_scan": "اسکن",
1376 "zcash_card_warning": "تا زمانی که این فرایند کامل نشده است، برنامه را نبندید؛ در غیر این صورت، این فرایند باید از ابتدا دوباره شروع شود."
1377 -}
\ No newline at end of file
1377 +}
res/values/strings_fr.arb
+1 -1
@@ -1377,4 +1377,4 @@
1377 "zcash_card_missing_funds": "Fonds manquants ?",
1378 "zcash_card_scan": "Scanner",
1379 "zcash_card_warning": "Ne fermez pas l'application tant que la procédure n'est pas terminée. Si vous le faites, ce processus devra redémarrer depuis le début."
1380 -}
\ No newline at end of file
1380 +}
res/values/strings_gn.arb
+1 -1
@@ -1116,4 +1116,4 @@
1116 "zcash_card_missing_funds": "¿Nde fondo okañy?",
1117 "zcash_card_scan": "Escanear",
1118 "zcash_card_warning": "Ani remboty pe app pe procedimiento opa hag̃ua, rejapo ramo upéicha ko proceso tekotevẽta oñepyrũ jey cero guive."
1119 -}
\ No newline at end of file
1119 +}
res/values/strings_ha.arb
+1 -1
@@ -1380,4 +1380,4 @@
1380 "zcash_card_missing_funds": "Kuɗi sun ɓace?",
1381 "zcash_card_scan": "Duba",
1382 "zcash_card_warning": "Kada ku rufe manhajar har sai an kammala aikin; idan kun yi haka, wannan tsari zai buƙaci a sake farawa daga farko."
1383 -}
\ No newline at end of file
1383 +}
res/values/strings_hi.arb
+2 -2
@@ -736,8 +736,8 @@
736 "payjoin_unavailable_sheet_title": "Payjoin उपलब्ध क्यों नहीं है?",
737 "payment_id": "भुगतान आईडी: ",
738 "payment_made_easy": "भुगतान करना आसान",
739 - "payment_was_received": "आपका भुगतान प्राप्त हो गया।",
739 "Payment_was_received": "आपका भुगतान प्राप्त हो गया था।",
740 + "payment_was_received": "आपका भुगतान प्राप्त हो गया।",
741 "payments": "भुगतान",
742 "pending": " (लंबित)",
743 "percentageOf": "${amount} का",
@@ -1379,4 +1379,4 @@
1379 "zcash_card_missing_funds": "फंड गायब हैं?",
1380 "zcash_card_scan": "स्कैन",
1381 "zcash_card_warning": "प्रक्रिया पूरी होने तक ऐप बंद न करें। यदि आप ऐसा करते हैं, तो यह प्रक्रिया शुरू से फिर से शुरू करनी होगी।"
1382 -}
\ No newline at end of file
1382 +}
res/values/strings_hr.arb
+1 -1
@@ -1377,4 +1377,4 @@
1377 "zcash_card_missing_funds": "Nedostaju sredstva?",
1378 "zcash_card_scan": "Skeniraj",
1379 "zcash_card_warning": "Ne zatvarajte aplikaciju dok se postupak ne dovrši; ako to učinite, postupak će se morati ponovno pokrenuti ispočetka."
1380 -}
\ No newline at end of file
1380 +}
res/values/strings_hy.arb
+1 -1
@@ -1375,4 +1375,4 @@
1375 "zcash_card_missing_funds": "Միջոցները բացակա՞յում են",
1376 "zcash_card_scan": "Սկանավորել",
1377 "zcash_card_warning": "Մի փակեք հավելվածը մինչև ընթացակարգի ավարտը, քանի որ հակառակ դեպքում այս գործընթացը պետք է վերագործարկվի զրոյից։"
1378 -}
\ No newline at end of file
1378 +}
res/values/strings_id.arb
+1 -1
@@ -1380,4 +1380,4 @@
1380 "zcash_card_missing_funds": "Dana hilang?",
1381 "zcash_card_scan": "Pindai",
1382 "zcash_card_warning": "Jangan tutup aplikasi sampai prosedur selesai. Jika Anda melakukannya, proses ini harus dimulai ulang dari awal."
1383 -}
\ No newline at end of file
1383 +}
res/values/strings_it.arb
+1 -1
@@ -1379,4 +1379,4 @@
1379 "zcash_card_missing_funds": "Fondi mancanti?",
1380 "zcash_card_scan": "Scansiona",
1381 "zcash_card_warning": "Non chiudere l'app finché la procedura non è completata, altrimenti sarà necessario riavviare il processo da zero."
1382 -}
\ No newline at end of file
1382 +}
res/values/strings_ja.arb
+1 -1
@@ -1377,4 +1377,4 @@
1377 "zcash_card_missing_funds": "資金が見当たりませんか?",
1378 "zcash_card_scan": "スキャン",
1379 "zcash_card_warning": "手順が完了するまでアプリを閉じないでください。閉じると、このプロセスを最初からやり直す必要があります。"
1380 -}
\ No newline at end of file
1380 +}
res/values/strings_ko.arb
+1 -1
@@ -1377,4 +1377,4 @@
1377 "zcash_card_missing_funds": "자금이 사라졌나요?",
1378 "zcash_card_scan": "스캔",
1379 "zcash_card_warning": "절차가 완료될 때까지 앱을 닫지 마십시오. 닫으면 이 과정을 처음부터 다시 시작해야 합니다."
1380 -}
\ No newline at end of file
1380 +}
res/values/strings_my.arb
+1 -1
@@ -1376,4 +1376,4 @@
1376 "zcash_card_missing_funds": "ငွေကြေး ပျောက်ဆုံးနေပါသလား?",
1377 "zcash_card_scan": "စကင်",
1378 "zcash_card_warning": "လုပ်ငန်းစဉ် ပြီးဆုံးသည်အထိ အက်ပ်ကို မပိတ်ပါနှင့်။ ပိတ်လိုက်ပါက ဤလုပ်ငန်းစဉ်ကို အစမှ ပြန်လည်စတင်ရမည်ဖြစ်သည်။"
1379 -}
\ No newline at end of file
1379 +}
res/values/strings_nl.arb
+1 -1
@@ -1374,4 +1374,4 @@
1374 "zcash_card_missing_funds": "Fondsen ontbreken?",
1375 "zcash_card_scan": "Scannen",
1376 "zcash_card_warning": "Sluit de app niet voordat de procedure is voltooid. Als je dit wel doet, moet dit proces helemaal opnieuw worden gestart."
1377 -}
\ No newline at end of file
1377 +}
res/values/strings_pl.arb
+1 -1
@@ -1375,4 +1375,4 @@
1375 "zcash_card_missing_funds": "Brakuje środków?",
1376 "zcash_card_scan": "Skanuj",
1377 "zcash_card_warning": "Nie zamykaj aplikacji do czasu zakończenia procedury. Jeśli to zrobisz, proces będzie musiał rozpocząć się od nowa."
1378 -}
\ No newline at end of file
1378 +}
res/values/strings_pt.arb
+1 -1
@@ -1379,4 +1379,4 @@
1379 "zcash_card_missing_funds": "Fundos em falta?",
1380 "zcash_card_scan": "Escanear",
1381 "zcash_card_warning": "Não feche o aplicativo até que o procedimento seja concluído; se você fizer isso, esse processo precisará ser reiniciado do zero."
1382 -}
\ No newline at end of file
1382 +}
res/values/strings_ru.arb
+1 -1
@@ -1377,4 +1377,4 @@
1377 "zcash_card_missing_funds": "Не хватает средств?",
1378 "zcash_card_scan": "Сканировать",
1379 "zcash_card_warning": "Не закрывайте приложение до завершения процедуры. Если вы это сделаете, процесс придется перезапустить с нуля."
1380 -}
\ No newline at end of file
1380 +}
res/values/strings_th.arb
+1 -1
@@ -1376,4 +1376,4 @@
1376 "zcash_card_missing_funds": "ยอดเงินหายไป?",
1377 "zcash_card_scan": "สแกน",
1378 "zcash_card_warning": "อย่าปิดแอปจนกว่าขั้นตอนจะเสร็จสิ้น หากคุณปิดแอป กระบวนการนี้จะต้องเริ่มใหม่ตั้งแต่ต้น"
1379 -}
\ No newline at end of file
1379 +}
res/values/strings_tl.arb
+1 -1
@@ -1376,4 +1376,4 @@
1376 "zcash_card_missing_funds": "Nawawalang pondo?",
1377 "zcash_card_scan": "I-scan",
1378 "zcash_card_warning": "Huwag isara ang app hanggang sa makumpleto ang proseso; kung gagawin mo ito, kakailanganing magsimula muli mula sa simula."
1379 -}
\ No newline at end of file
1379 +}
res/values/strings_tr.arb
+1 -1
@@ -1376,4 +1376,4 @@
1376 "zcash_card_missing_funds": "Bakiye eksik mi?",
1377 "zcash_card_scan": "Tara",
1378 "zcash_card_warning": "İşlem tamamlanana kadar uygulamayı kapatmayın; aksi takdirde bu işlemin baştan yeniden başlatılması gerekecektir."
1379 -}
\ No newline at end of file
1379 +}
res/values/strings_uk.arb
+1 -1
@@ -1377,4 +1377,4 @@
1377 "zcash_card_missing_funds": "Зникли кошти?",
1378 "zcash_card_scan": "Сканувати",
1379 "zcash_card_warning": "Не закривайте застосунок, доки процедура не завершиться. Якщо ви це зробите, цей процес потрібно буде перезапустити з нуля."
1380 -}
\ No newline at end of file
1380 +}
res/values/strings_ur.arb
+1 -1
@@ -1378,4 +1378,4 @@
1378 "zcash_card_missing_funds": "فنڈز غائب ہیں؟",
1379 "zcash_card_scan": "اسکین کریں",
1380 "zcash_card_warning": "طریقہ کار مکمل ہونے تک ایپ بند نہ کریں۔ اگر آپ ایسا کریں گے تو یہ عمل شروع سے دوبارہ شروع کرنا پڑے گا۔"
1381 -}
\ No newline at end of file
1381 +}
res/values/strings_vi.arb
+1 -1
@@ -1373,4 +1373,4 @@
1373 "zcash_card_missing_funds": "Thiếu tiền?",
1374 "zcash_card_scan": "Quét",
1375 "zcash_card_warning": "Không đóng ứng dụng cho đến khi quy trình hoàn tất; nếu bạn làm vậy, quy trình này sẽ phải bắt đầu lại từ đầu."
1376 -}
\ No newline at end of file
1376 +}
res/values/strings_yo.arb
+1 -1
@@ -1377,4 +1377,4 @@
1377 "zcash_card_missing_funds": "Ṣe owó rẹ sọnù?",
1378 "zcash_card_scan": "Ṣàwárí",
1379 "zcash_card_warning": "Maṣe pa ohun elo naa titi ilana naa yoo fi pari; bí o bá ṣe bẹ́ẹ̀, ilana yìí yóò ní láti tún bẹ̀rẹ̀ láti ìbẹ̀rẹ̀."
1380 -}
\ No newline at end of file
1380 +}
res/values/strings_zh.arb
+1 -1
@@ -1376,4 +1376,4 @@
1376 "zcash_card_missing_funds": "资金不见了?",
1377 "zcash_card_scan": "扫描",
1378 "zcash_card_warning": "在该过程完成之前请勿关闭应用程序,否则该过程将需要从头重新开始。"
1379 -}
\ No newline at end of file
1379 +}