diff --git a/assets/images/info_icon.svg b/assets/images/info_icon.svg new file mode 100644 index 000000000..31518cd17 --- /dev/null +++ b/assets/images/info_icon.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/cw_bitcoin/lib/bitcoin_address_record.dart b/cw_bitcoin/lib/bitcoin_address_record.dart index 400e325be..d6de05051 100644 --- a/cw_bitcoin/lib/bitcoin_address_record.dart +++ b/cw_bitcoin/lib/bitcoin_address_record.dart @@ -54,6 +54,8 @@ abstract class BaseBitcoinAddressRecord { BitcoinAddressType type; + String get derivationPath; + String toJSON(); } @@ -118,6 +120,31 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord { String? scriptHash; + static int _purposeForType(BitcoinAddressType type) { + if (type == P2pkhAddressType.p2pkh) return 44; + if (type == P2shAddressType.p2wpkhInP2sh) return 49; + if (type == SegwitAddresType.p2wsh) return 48; + if (type == SegwitAddresType.p2tr) return 86; + return 84; + } + + int _coinTypeForNetwork() { + if (!(network?.isMainnet ?? true)) return 1; + + switch (network) { + case BitcoinNetwork.mainnet: + return 0; + case LitecoinNetwork.mainnet: + return 2; + case BitcoinCashNetwork.mainnet: + return 145; + case DogecoinNetwork.mainnet: + return 3; + default: + return 0; + } + } + String getScriptHash(BasedUtxoNetwork network) { if (scriptHash != null) return scriptHash!; try { @@ -127,6 +154,21 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord { } return scriptHash!; } + @override + String get derivationPath { + if (type == SegwitAddresType.mweb) { + return "m/1000'/$index"; + } + + final coinType = _coinTypeForNetwork(); + final purpose = _purposeForType(type); + final accountPath = isLegacyDerivation + ? electrum_path + : "m/$purpose'/$coinType'/0'"; + + final chain = isHidden ? 1 : 0; + return "$accountPath/$chain/$index"; + } @override String toJSON() => json.encode({ @@ -186,6 +228,9 @@ class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord { final String? silentPaymentTweak; final String spendDerivationPath; + @override + String get derivationPath => spendDerivationPath; + @override String toJSON() => json.encode({ 'address': address, diff --git a/cw_core/lib/get_height_by_date.dart b/cw_core/lib/get_height_by_date.dart index 4786336af..58155a7fb 100644 --- a/cw_core/lib/get_height_by_date.dart +++ b/cw_core/lib/get_height_by_date.dart @@ -1,163 +1,12 @@ import 'package:cw_core/utils/proxy_wrapper.dart'; import 'package:cw_core/utils/print_verbose.dart'; import 'package:intl/intl.dart'; +import 'package:cw_core/get_height_by_date_xmr.dart'; import 'dart:convert'; // FIXME: Hardcoded values; Works only for monero -final dateFormat = DateFormat('yyyy-MM'); -final dates = { - "2014-5": 18844, - "2014-6": 65406, - "2014-7": 108882, - "2014-8": 153594, - "2014-9": 198072, - "2014-10": 241088, - "2014-11": 285305, - "2014-12": 328069, - "2015-1": 372369, - "2015-2": 416505, - "2015-3": 456631, - "2015-4": 501084, - "2015-5": 543973, - "2015-6": 588326, - "2015-7": 631187, - "2015-8": 675484, - "2015-9": 719725, - "2015-10": 762463, - "2015-11": 806528, - "2015-12": 849041, - "2016-1": 892866, - "2016-2": 936736, - "2016-3": 977691, - "2016-4": 1015848, - "2016-5": 1037417, - "2016-6": 1059651, - "2016-7": 1081269, - "2016-8": 1103630, - "2016-9": 1125983, - "2016-10": 1147617, - "2016-11": 1169779, - "2016-12": 1191402, - "2017-1": 1213861, - "2017-2": 1236197, - "2017-3": 1256358, - "2017-4": 1278622, - "2017-5": 1300239, - "2017-6": 1322564, - "2017-7": 1344225, - "2017-8": 1366664, - "2017-9": 1389113, - "2017-10": 1410738, - "2017-11": 1433039, - "2017-12": 1454639, - "2018-1": 1477201, - "2018-2": 1499599, - "2018-3": 1519796, - "2018-4": 1542067, - "2018-5": 1562861, - "2018-6": 1585135, - "2018-7": 1606715, - "2018-8": 1629017, - "2018-9": 1651347, - "2018-10": 1673031, - "2018-11": 1695128, - "2018-12": 1716687, - "2019-1": 1738923, - "2019-2": 1761435, - "2019-3": 1781681, - "2019-4": 1803081, - "2019-5": 1824671, - "2019-6": 1847005, - "2019-7": 1868590, - "2019-8": 1890552, - "2019-9": 1912212, - "2019-10": 1932200, - "2019-11": 1957040, - "2019-12": 1978090, - "2020-1": 2001290, - "2020-2": 2022688, - "2020-3": 2043987, - "2020-4": 2066536, - "2020-5": 2090797, - "2020-6": 2111633, - "2020-7": 2131433, - "2020-8": 2153983, - "2020-9": 2176466, - "2020-10": 2198453, - "2020-11": 2220000, - "2020-12": 2242240, - "2021-1": 2264584, - "2021-2": 2286892, - "2021-3": 2307079, - "2021-4": 2329385, - "2021-5": 2351004, - "2021-6": 2373306, - "2021-7": 2394882, - "2021-8": 2417162, - "2021-9": 2439490, - "2021-10": 2461020, - "2021-11": 2483377, - "2021-12": 2504932, - "2022-1": 2527316, - "2022-2": 2549605, - "2022-3": 2569711, - "2022-4": 2591995, - "2022-5": 2613603, - "2022-6": 2635840, - "2022-7": 2657395, - "2022-8": 2679705, - "2022-9": 2701991, - "2022-10": 2723607, - "2022-11": 2745899, - "2022-12": 2767427, - "2023-1": 2789763, - "2023-2": 2811996, - "2023-3": 2832118, - "2023-4": 2854365, - "2023-5": 2875972, - "2023-6": 2898234, - "2023-7": 2919771, - "2023-8": 2942045, - "2023-9": 2964280, - "2023-10": 2985937, - "2023-11": 3008178, - "2023-12": 3029759 -}; - -int getMoneroHeigthByDate({required DateTime date}) { - final raw = '${date.year}' + '-' + '${date.month}'; - final lastHeight = dates.values.last; - int startHeight; - int endHeight; - int height = 0; - - try { - if ((dates[raw] == null) || (dates[raw] == lastHeight)) { - startHeight = dates.values.toList()[dates.length - 2]; - endHeight = dates.values.toList()[dates.length - 1]; - final heightPerDay = (endHeight - startHeight) / 31; - final endDateRaw = dates.keys.toList()[dates.length - 1].split('-'); - final endYear = int.parse(endDateRaw[0]); - final endMonth = int.parse(endDateRaw[1]); - final endDate = DateTime(endYear, endMonth); - final differenceInDays = date.difference(endDate).inDays; - final daysHeight = (differenceInDays * heightPerDay).round(); - height = endHeight + daysHeight; - } else { - startHeight = dates[raw]!; - final index = dates.values.toList().indexOf(startHeight); - endHeight = dates.values.toList()[index + 1]; - final heightPerDay = ((endHeight - startHeight) / 31).round(); - final daysHeight = (date.day - 1) * heightPerDay; - height = startHeight + daysHeight - heightPerDay; - } - } catch (e) { - printV(e.toString()); - } - - return height; -} +int getMoneroHeigthByDate({required DateTime date}) => MoneroHeight.getBlockHeightByTime(date..subtract(Duration(days: 1))); const havenDates = { "2023-05": 1352995, @@ -223,6 +72,7 @@ const havenDates = { "2018-04": 32000, "2018-03": 8500 }; +final dateFormat = DateFormat('yyyy-MM'); DateTime formatMapKey(String key) => dateFormat.parse(key); @@ -234,9 +84,10 @@ int getHavenHeightByDate({required DateTime date}) { } Future getHavenCurrentHeight() async { - final req = await ProxyWrapper().getHttpClient() - .getUrl(Uri.parse('https://explorer.havenprotocol.org/api/networkinfo')) - .timeout(Duration(seconds: 15)); + final req = await ProxyWrapper() + .getHttpClient() + .getUrl(Uri.parse('https://explorer.havenprotocol.org/api/networkinfo')) + .timeout(Duration(seconds: 15)); final response = await req.close(); final stringResponse = await response.transform(utf8.decoder).join(); @@ -273,9 +124,11 @@ const bitcoinDates = { }; Future getBitcoinHeightByDateAPI({required DateTime date}) async { - final req = await ProxyWrapper().getHttpClient() - .getUrl(Uri.parse("https://mempool.cakewallet.com/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}")) - .timeout(Duration(seconds: 15)); + final req = await ProxyWrapper() + .getHttpClient() + .getUrl(Uri.parse( + "https://mempool.cakewallet.com/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}")) + .timeout(Duration(seconds: 15)); final response = await req.close(); final stringResponse = await response.transform(utf8.decoder).join(); diff --git a/cw_core/lib/get_height_by_date_xmr.dart b/cw_core/lib/get_height_by_date_xmr.dart new file mode 100644 index 000000000..16a1b2002 --- /dev/null +++ b/cw_core/lib/get_height_by_date_xmr.dart @@ -0,0 +1,422 @@ + +class MoneroHeight { + // for i in $(seq 1 364); do echo "_Checkpoint(_t($(curl https://xmrchain.net/block/${i}0000 | grep -E '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}' | xargs | sed 's/ /\n/g' | head -5 | tail -1 | tr '()' ' ' | sed 's/ /\n/g' | head -2 | xargs)), ${i}0000),"; done > points.txt + static final List<_Checkpoint> _points = [ + _Checkpoint(1398386790, 10000), + _Checkpoint(1398970097, 20000), + _Checkpoint(1399529049, 30000), + _Checkpoint(1400107914, 40000), + _Checkpoint(1400673084, 50000), + _Checkpoint(1401259431, 60000), + _Checkpoint(1401861514, 70000), + _Checkpoint(1402455081, 80000), + _Checkpoint(1403051337, 90000), + _Checkpoint(1403639801, 100000), + _Checkpoint(1404238831, 110000), + _Checkpoint(1404841666, 120000), + _Checkpoint(1405444927, 130000), + _Checkpoint(1406035044, 140000), + _Checkpoint(1406634825, 150000), + _Checkpoint(1407238604, 160000), + _Checkpoint(1407838442, 170000), + _Checkpoint(1408443936, 180000), + _Checkpoint(1409041095, 190000), + _Checkpoint(1409644412, 200000), + _Checkpoint(1410247699, 210000), + _Checkpoint(1410851018, 220000), + _Checkpoint(1411455976, 230000), + _Checkpoint(1412059180, 240000), + _Checkpoint(1412661506, 250000), + _Checkpoint(1413267445, 260000), + _Checkpoint(1413873271, 270000), + _Checkpoint(1414480925, 280000), + _Checkpoint(1415086077, 290000), + _Checkpoint(1415690591, 300000), + _Checkpoint(1416296909, 310000), + _Checkpoint(1416902704, 320000), + _Checkpoint(1417507901, 330000), + _Checkpoint(1418109054, 340000), + _Checkpoint(1418722232, 350000), + _Checkpoint(1419326271, 360000), + _Checkpoint(1419928389, 370000), + _Checkpoint(1420541216, 380000), + _Checkpoint(1421145579, 390000), + _Checkpoint(1421749732, 400000), + _Checkpoint(1422354623, 410000), + _Checkpoint(1422956207, 420000), + _Checkpoint(1423562393, 430000), + _Checkpoint(1424166115, 440000), + _Checkpoint(1424767351, 450000), + _Checkpoint(1425371690, 460000), + _Checkpoint(1425975620, 470000), + _Checkpoint(1426579077, 480000), + _Checkpoint(1427182546, 490000), + _Checkpoint(1427785048, 500000), + _Checkpoint(1428385900, 510000), + _Checkpoint(1428990297, 520000), + _Checkpoint(1429593770, 530000), + _Checkpoint(1430197340, 540000), + _Checkpoint(1430803986, 550000), + _Checkpoint(1431408119, 560000), + _Checkpoint(1432011390, 570000), + _Checkpoint(1432613317, 580000), + _Checkpoint(1433222583, 590000), + _Checkpoint(1433825715, 600000), + _Checkpoint(1434431094, 610000), + _Checkpoint(1435033265, 620000), + _Checkpoint(1435636924, 630000), + _Checkpoint(1436243604, 640000), + _Checkpoint(1436848163, 650000), + _Checkpoint(1437455928, 660000), + _Checkpoint(1438056769, 670000), + _Checkpoint(1438662194, 680000), + _Checkpoint(1439267688, 690000), + _Checkpoint(1439872751, 700000), + _Checkpoint(1440479855, 710000), + _Checkpoint(1441084930, 720000), + _Checkpoint(1441690778, 730000), + _Checkpoint(1442300128, 740000), + _Checkpoint(1442902966, 750000), + _Checkpoint(1443510081, 760000), + _Checkpoint(1444120229, 770000), + _Checkpoint(1444725863, 780000), + _Checkpoint(1445334248, 790000), + _Checkpoint(1445938467, 800000), + _Checkpoint(1446548650, 810000), + _Checkpoint(1447157167, 820000), + _Checkpoint(1447766950, 830000), + _Checkpoint(1448375042, 840000), + _Checkpoint(1448982313, 850000), + _Checkpoint(1449591976, 860000), + _Checkpoint(1450206082, 870000), + _Checkpoint(1450817995, 880000), + _Checkpoint(1451431001, 890000), + _Checkpoint(1452044620, 900000), + _Checkpoint(1452654325, 910000), + _Checkpoint(1453271464, 920000), + _Checkpoint(1453874045, 930000), + _Checkpoint(1454490333, 940000), + _Checkpoint(1455096906, 950000), + _Checkpoint(1455704830, 960000), + _Checkpoint(1456315340, 970000), + _Checkpoint(1456926968, 980000), + _Checkpoint(1457536684, 990000), + _Checkpoint(1458145453, 1000000), + _Checkpoint(1458780543, 1010000), + _Checkpoint(1459961331, 1020000), + _Checkpoint(1461174469, 1030000), + _Checkpoint(1462375809, 1040000), + _Checkpoint(1463578591, 1050000), + _Checkpoint(1464785682, 1060000), + _Checkpoint(1465981307, 1070000), + _Checkpoint(1467185150, 1080000), + _Checkpoint(1468365704, 1090000), + _Checkpoint(1469573151, 1100000), + _Checkpoint(1470777161, 1110000), + _Checkpoint(1471975662, 1120000), + _Checkpoint(1473164186, 1130000), + _Checkpoint(1474374066, 1140000), + _Checkpoint(1475577458, 1150000), + _Checkpoint(1476776898, 1160000), + _Checkpoint(1477990372, 1170000), + _Checkpoint(1479187102, 1180000), + _Checkpoint(1480378008, 1190000), + _Checkpoint(1481575804, 1200000), + _Checkpoint(1482772399, 1210000), + _Checkpoint(1483965031, 1220000), + _Checkpoint(1485170094, 1230000), + _Checkpoint(1486369447, 1240000), + _Checkpoint(1487569956, 1250000), + _Checkpoint(1488775148, 1260000), + _Checkpoint(1489970122, 1270000), + _Checkpoint(1491168799, 1280000), + _Checkpoint(1492371569, 1290000), + _Checkpoint(1493568547, 1300000), + _Checkpoint(1494770503, 1310000), + _Checkpoint(1495965162, 1320000), + _Checkpoint(1497168519, 1330000), + _Checkpoint(1498361038, 1340000), + _Checkpoint(1499552117, 1350000), + _Checkpoint(1500747868, 1360000), + _Checkpoint(1501946180, 1370000), + _Checkpoint(1503149952, 1380000), + _Checkpoint(1504330700, 1390000), + _Checkpoint(1505525706, 1400000), + _Checkpoint(1506725266, 1410000), + _Checkpoint(1507924408, 1420000), + _Checkpoint(1509129536, 1430000), + _Checkpoint(1510332372, 1440000), + _Checkpoint(1511529796, 1450000), + _Checkpoint(1512713363, 1460000), + _Checkpoint(1513909535, 1470000), + _Checkpoint(1515100139, 1480000), + _Checkpoint(1516298977, 1490000), + _Checkpoint(1517489351, 1500000), + _Checkpoint(1518688093, 1510000), + _Checkpoint(1519885580, 1520000), + _Checkpoint(1521088410, 1530000), + _Checkpoint(1522289764, 1540000), + _Checkpoint(1523589333, 1550000), + _Checkpoint(1524783179, 1560000), + _Checkpoint(1525991638, 1570000), + _Checkpoint(1527194575, 1580000), + _Checkpoint(1528395704, 1590000), + _Checkpoint(1529603343, 1600000), + _Checkpoint(1530796888, 1610000), + _Checkpoint(1531995687, 1620000), + _Checkpoint(1533197982, 1630000), + _Checkpoint(1534403578, 1640000), + _Checkpoint(1535600184, 1650000), + _Checkpoint(1536793547, 1660000), + _Checkpoint(1537992755, 1670000), + _Checkpoint(1539198355, 1680000), + _Checkpoint(1540414062, 1690000), + _Checkpoint(1541612717, 1700000), + _Checkpoint(1542815406, 1710000), + _Checkpoint(1544019553, 1720000), + _Checkpoint(1545229810, 1730000), + _Checkpoint(1546431793, 1740000), + _Checkpoint(1547615007, 1750000), + _Checkpoint(1548812515, 1760000), + _Checkpoint(1549998027, 1770000), + _Checkpoint(1551198085, 1780000), + _Checkpoint(1552503513, 1790000), + _Checkpoint(1553698458, 1800000), + _Checkpoint(1554900519, 1810000), + _Checkpoint(1556102453, 1820000), + _Checkpoint(1557301054, 1830000), + _Checkpoint(1558508921, 1840000), + _Checkpoint(1559706132, 1850000), + _Checkpoint(1560908667, 1860000), + _Checkpoint(1562106679, 1870000), + _Checkpoint(1563311957, 1880000), + _Checkpoint(1564511944, 1890000), + _Checkpoint(1565709489, 1900000), + _Checkpoint(1566910782, 1910000), + _Checkpoint(1568109052, 1920000), + _Checkpoint(1569319349, 1930000), + _Checkpoint(1570518236, 1940000), + _Checkpoint(1571718656, 1950000), + _Checkpoint(1572919811, 1960000), + _Checkpoint(1574128184, 1970000), + _Checkpoint(1575292812, 1980000), + _Checkpoint(1576479575, 1990000), + _Checkpoint(1577680194, 2000000), + _Checkpoint(1578876107, 2010000), + _Checkpoint(1580075963, 2020000), + _Checkpoint(1581273916, 2030000), + _Checkpoint(1582472927, 2040000), + _Checkpoint(1583679893, 2050000), + _Checkpoint(1584883948, 2060000), + _Checkpoint(1586084634, 2070000), + _Checkpoint(1587287479, 2080000), + _Checkpoint(1588480325, 2090000), + _Checkpoint(1589683808, 2100000), + _Checkpoint(1590881378, 2110000), + _Checkpoint(1592087857, 2120000), + _Checkpoint(1593277684, 2130000), + _Checkpoint(1594490084, 2140000), + _Checkpoint(1595692597, 2150000), + _Checkpoint(1596887172, 2160000), + _Checkpoint(1598105106, 2170000), + _Checkpoint(1599306018, 2180000), + _Checkpoint(1600510218, 2190000), + _Checkpoint(1601703776, 2200000), + _Checkpoint(1602893696, 2210000), + _Checkpoint(1604112554, 2220000), + _Checkpoint(1605313298, 2230000), + _Checkpoint(1606513918, 2240000), + _Checkpoint(1607716100, 2250000), + _Checkpoint(1608912594, 2260000), + _Checkpoint(1610111416, 2270000), + _Checkpoint(1611312080, 2280000), + _Checkpoint(1612512703, 2290000), + _Checkpoint(1613707976, 2300000), + _Checkpoint(1614906615, 2310000), + _Checkpoint(1616110597, 2320000), + _Checkpoint(1617306552, 2330000), + _Checkpoint(1618511460, 2340000), + _Checkpoint(1619709663, 2350000), + _Checkpoint(1620910784, 2360000), + _Checkpoint(1622108971, 2370000), + _Checkpoint(1623312679, 2380000), + _Checkpoint(1624516914, 2390000), + _Checkpoint(1625715884, 2400000), + _Checkpoint(1626915471, 2410000), + _Checkpoint(1628116823, 2420000), + _Checkpoint(1629318052, 2430000), + _Checkpoint(1630517187, 2440000), + _Checkpoint(1631717800, 2450000), + _Checkpoint(1632918546, 2460000), + _Checkpoint(1634124541, 2470000), + _Checkpoint(1635324499, 2480000), + _Checkpoint(1636519414, 2490000), + _Checkpoint(1637720692, 2500000), + _Checkpoint(1638925683, 2510000), + _Checkpoint(1640127154, 2520000), + _Checkpoint(1641321384, 2530000), + _Checkpoint(1642524155, 2540000), + _Checkpoint(1643722767, 2550000), + _Checkpoint(1644923112, 2560000), + _Checkpoint(1646128603, 2570000), + _Checkpoint(1647331058, 2580000), + _Checkpoint(1648530154, 2590000), + _Checkpoint(1649731449, 2600000), + _Checkpoint(1650930600, 2610000), + _Checkpoint(1652137128, 2620000), + _Checkpoint(1653338800, 2630000), + _Checkpoint(1654539762, 2640000), + _Checkpoint(1655747917, 2650000), + _Checkpoint(1656945266, 2660000), + _Checkpoint(1658150587, 2670000), + _Checkpoint(1659349371, 2680000), + _Checkpoint(1660553735, 2690000), + _Checkpoint(1661752700, 2700000), + _Checkpoint(1662945664, 2710000), + _Checkpoint(1664150159, 2720000), + _Checkpoint(1665357200, 2730000), + _Checkpoint(1666557130, 2740000), + _Checkpoint(1667758004, 2750000), + _Checkpoint(1668963041, 2760000), + _Checkpoint(1670159857, 2770000), + _Checkpoint(1671366967, 2780000), + _Checkpoint(1672562400, 2790000), + _Checkpoint(1673769923, 2800000), + _Checkpoint(1674973607, 2810000), + _Checkpoint(1676162080, 2820000), + _Checkpoint(1677371812, 2830000), + _Checkpoint(1678576821, 2840000), + _Checkpoint(1679780527, 2850000), + _Checkpoint(1680978762, 2860000), + _Checkpoint(1682185252, 2870000), + _Checkpoint(1683386854, 2880000), + _Checkpoint(1684586627, 2890000), + _Checkpoint(1685787011, 2900000), + _Checkpoint(1686993944, 2910000), + _Checkpoint(1688196910, 2920000), + _Checkpoint(1689392833, 2930000), + _Checkpoint(1690593379, 2940000), + _Checkpoint(1691812920, 2950000), + _Checkpoint(1693013768, 2960000), + _Checkpoint(1694214345, 2970000), + _Checkpoint(1695411856, 2980000), + _Checkpoint(1696602209, 2990000), + _Checkpoint(1697813342, 3000000), + _Checkpoint(1699012649, 3010000), + _Checkpoint(1700219506, 3020000), + _Checkpoint(1701417489, 3030000), + _Checkpoint(1702620638, 3040000), + _Checkpoint(1703824734, 3050000), + _Checkpoint(1705022552, 3060000), + _Checkpoint(1706223184, 3070000), + _Checkpoint(1707426775, 3080000), + _Checkpoint(1708628612, 3090000), + _Checkpoint(1709832655, 3100000), + _Checkpoint(1711037724, 3110000), + _Checkpoint(1712236145, 3120000), + _Checkpoint(1713439631, 3130000), + _Checkpoint(1714640176, 3140000), + _Checkpoint(1715838106, 3150000), + _Checkpoint(1717027647, 3160000), + _Checkpoint(1718238665, 3170000), + _Checkpoint(1719430906, 3180000), + _Checkpoint(1720643178, 3190000), + _Checkpoint(1721843329, 3200000), + _Checkpoint(1723042527, 3210000), + _Checkpoint(1724242564, 3220000), + _Checkpoint(1725445200, 3230000), + _Checkpoint(1726636517, 3240000), + _Checkpoint(1727845671, 3250000), + _Checkpoint(1729039416, 3260000), + _Checkpoint(1730243700, 3270000), + _Checkpoint(1731448260, 3280000), + _Checkpoint(1732645674, 3290000), + _Checkpoint(1733848630, 3300000), + _Checkpoint(1735045564, 3310000), + _Checkpoint(1736247165, 3320000), + _Checkpoint(1737444468, 3330000), + _Checkpoint(1738643351, 3340000), + _Checkpoint(1739839603, 3350000), + _Checkpoint(1741046630, 3360000), + _Checkpoint(1742243178, 3370000), + _Checkpoint(1743442732, 3380000), + _Checkpoint(1744648072, 3390000), + _Checkpoint(1745849558, 3400000), + _Checkpoint(1747049310, 3410000), + _Checkpoint(1748238277, 3420000), + _Checkpoint(1749449164, 3430000), + _Checkpoint(1750652323, 3440000), + _Checkpoint(1751852432, 3450000), + _Checkpoint(1753046298, 3460000), + _Checkpoint(1754249974, 3470000), + _Checkpoint(1755455410, 3480000), + _Checkpoint(1756666863, 3490000), + _Checkpoint(1757868614, 3500000), + _Checkpoint(1759061269, 3510000), + _Checkpoint(1760271644, 3520000), + _Checkpoint(1761476806, 3530000), + _Checkpoint(1762672780, 3540000), + _Checkpoint(1763878670, 3550000), + _Checkpoint(1765074231, 3560000), + _Checkpoint(1766276987, 3570000), + _Checkpoint(1767477623, 3580000), + _Checkpoint(1768680288, 3590000), + _Checkpoint(1769885820, 3600000), + _Checkpoint(1771090287, 3610000), + _Checkpoint(1772293937, 3620000), + _Checkpoint(1773490619, 3630000), + _Checkpoint(1774693829, 3640000), + ]; + + static int getBlockHeightByTime(DateTime time) { + final t = time.toUtc().millisecondsSinceEpoch; + + if (_points.isEmpty) return 0; + + if (t <= _points.first.timeMs) { + return 1; + } + + for (int i = 0; i < _points.length - 1; i++) { + final p0 = _points[i]; + final p1 = _points[i + 1]; + + if (t >= p0.timeMs && t < p1.timeMs) { + return _interpolate( + p0.height, + p1.height, + p0.timeMs, + p1.timeMs, + t, + ); + } + } + + final last = _points[_points.length - 1]; + final prev = _points[_points.length - 2]; + + final avgBlockTimeMs = (last.timeMs - prev.timeMs) / (last.height - prev.height); + + final blocksSinceLast = ((t - last.timeMs) / avgBlockTimeMs).floor(); + + return last.height + blocksSinceLast; + } + + static int _interpolate( + int h0, + int h1, + int t0, + int t1, + int t, + ) { + final ratio = (t - t0) / (t1 - t0); + return h0 + ((h1 - h0) * ratio).floor(); + } +} + +class _Checkpoint { + final int timeMs; + final int height; + + _Checkpoint(int timeSec, this.height) : timeMs = timeSec * 1000; +} diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index 62db2a63e..6f5b9bfa4 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -185,7 +185,8 @@ class CWBitcoin extends Bitcoin { txCount: addr.txCount, balance: addr.balance, isChange: addr.isHidden, - isLegacyDerivation: addr.isLegacyDerivation)) + isLegacyDerivation: addr.isLegacyDerivation, + derivationPath: addr.derivationPath)) .toList(); } @@ -574,7 +575,8 @@ class CWBitcoin extends Bitcoin { address: addr.address, txCount: addr.txCount, balance: addr.balance, - isChange: addr.isHidden)) + isChange: addr.isHidden, + derivationPath: addr.derivationPath)) .toList(); } @@ -589,7 +591,8 @@ class CWBitcoin extends Bitcoin { address: addr.address, txCount: addr.txCount, balance: addr.balance, - isChange: addr.isHidden)) + isChange: addr.isHidden, + derivationPath: addr.derivationPath)) .toList(); } diff --git a/lib/di.dart b/lib/di.dart index 715c88660..7a8a8185a 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -310,6 +310,7 @@ import 'buy/kryptonim/kryptonim.dart'; import 'buy/meld/meld_buy_provider.dart'; import 'dogecoin/dogecoin.dart'; import 'new-ui/viewmodels/card_customizer/card_customizer_bloc.dart'; +import 'new-ui/widgets/addresses_page/address_info.dart'; import 'src/screens/buy/buy_sell_page.dart'; final getIt = GetIt.instance; @@ -880,6 +881,11 @@ Future setup({ walletAddressEditOrCreateViewModel: getIt.get(param1: item))); + getIt.registerFactoryParam((dynamic item, _) => + AddressInfoPopup( + walletAddressEditOrCreateViewModel: + getIt.get(param1: item))); + getIt.registerFactoryParam((dynamic item, _) => ReceiveLabelModal( walletAddressEditOrCreateViewModel: diff --git a/lib/entities/new_ui_entities/list_item/list_item_regular_row.dart b/lib/entities/new_ui_entities/list_item/list_item_regular_row.dart index a9ef260d0..f6df44a25 100644 --- a/lib/entities/new_ui_entities/list_item/list_item_regular_row.dart +++ b/lib/entities/new_ui_entities/list_item/list_item_regular_row.dart @@ -15,13 +15,15 @@ class ListItemRegularRow extends ListItem { this.trailingWidget, this.truncateTrailingText = false, this.foregroundColor, - this.trailingIconSize + this.trailingIconSize, + this.copyableText }); final String? subtitle; final String? trailingText; final String? iconPath; final String? trailingIconPath; + final String? copyableText; final VoidCallback? onTap; final bool showArrow; final Widget? bottomWidget; diff --git a/lib/new-ui/pages/addresses_page.dart b/lib/new-ui/pages/addresses_page.dart index a7a81d282..9016116d0 100644 --- a/lib/new-ui/pages/addresses_page.dart +++ b/lib/new-ui/pages/addresses_page.dart @@ -4,6 +4,7 @@ import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/new-ui/long_press_popup.dart'; +import 'package:cake_wallet/new-ui/widgets/addresses_page/address_info.dart'; import 'package:cake_wallet/new-ui/widgets/addresses_page/address_label_input.dart'; import 'package:cake_wallet/new-ui/widgets/coins_page/cards/balance_card.dart'; import 'package:cake_wallet/new-ui/widgets/long_press_menu.dart'; @@ -355,6 +356,15 @@ class AddressRow extends StatelessWidget { onAddressHidden(); }, color: Theme.of(context).colorScheme.error), + LongPressMenuItem( + label: 'Info', + iconPath: "assets/images/info_icon.svg", + onSelected: () async { + Navigator.of(context, rootNavigator: true).pop(); + await showPopUp( + context: context, + builder: (context) => getIt.get(param1: item)); + }), ], ), child: AnimatedContainer( diff --git a/lib/new-ui/widgets/addresses_page/address_info.dart b/lib/new-ui/widgets/addresses_page/address_info.dart new file mode 100644 index 000000000..310b3d4e4 --- /dev/null +++ b/lib/new-ui/widgets/addresses_page/address_info.dart @@ -0,0 +1,46 @@ +import 'dart:ui'; + +import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart'; +import 'package:flutter/material.dart'; + +class AddressInfoPopup extends StatelessWidget { + const AddressInfoPopup({ + super.key, + required this.walletAddressEditOrCreateViewModel, + }); + + final WalletAddressEditOrCreateViewModel walletAddressEditOrCreateViewModel; + + @override + Widget build(BuildContext context) { + return BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surfaceContainerHigh, + borderRadius: BorderRadiusGeometry.lerp( + BorderRadius.circular(12), + BorderRadius.circular(24), + 0.5, + ), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + Text('Index: ${walletAddressEditOrCreateViewModel.index}'), + SizedBox(height: 16), + Text( + 'Derivation Path: ${walletAddressEditOrCreateViewModel.derivationPath}'), + ], + ), + ), + ), + ]), + ); + } +} diff --git a/lib/new-ui/widgets/coins_page/assets_history/transaction_details_modal.dart b/lib/new-ui/widgets/coins_page/assets_history/transaction_details_modal.dart index 079b008c8..f7e6c952f 100644 --- a/lib/new-ui/widgets/coins_page/assets_history/transaction_details_modal.dart +++ b/lib/new-ui/widgets/coins_page/assets_history/transaction_details_modal.dart @@ -99,10 +99,7 @@ class _TransactionDetailsModalState extends State { item.value.length > 25; return ListItemRegularRow( - onTap: () { - Clipboard.setData( - ClipboardData(text: item.value)); - }, + copyableText: item.value, showArrow: false, keyValue: ((item.key as ValueKey?)?.value as String?) ?? @@ -192,21 +189,24 @@ class _TransactionDetailsModalState extends State { } Widget _buildTrailingWIdget(TransactionDetailsListItem item) { - return switch (item.runtimeType) { - ConfirmationsListItem => Row( - children: [ - Text((item as ConfirmationsListItem).current.toString(), - style: TextStyle(color: Theme.of(context).colorScheme.primary)), - if (item.needed > 0) - Text("/${item.needed}", - style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)) - ], - ), - _ => Text( - item.value, - style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant), - ) - }; + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4.0), + child: switch (item.runtimeType) { + ConfirmationsListItem => Row( + children: [ + Text((item as ConfirmationsListItem).current.toString(), + style: TextStyle(color: Theme.of(context).colorScheme.primary)), + if (item.needed > 0) + Text("/${item.needed}", + style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)) + ], + ), + _ => Text( + item.value, + style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant), + ) + }, + ); } Widget _buildBottomWidget(TransactionDetailsListItem item) { diff --git a/lib/new-ui/widgets/copy_wrapper.dart b/lib/new-ui/widgets/copy_wrapper.dart new file mode 100644 index 000000000..254d02f5d --- /dev/null +++ b/lib/new-ui/widgets/copy_wrapper.dart @@ -0,0 +1,59 @@ +import 'dart:io'; + +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class CopyWrapper extends StatefulWidget { + const CopyWrapper( + {super.key, + this.data, + required this.builder, + this.duration = const Duration(milliseconds: 1200)}); + + final ClipboardData? data; + final Widget Function(BuildContext, bool) builder; + final Duration duration; + + @override + State createState() => _CopyWrapperState(); +} + +class _CopyWrapperState extends State { + bool copied = false; + + void handleCopy() async { + if (widget.data == null) return; + Clipboard.setData(widget.data!); + if (await shouldShowCopied()) { + setState(() => copied = true); + Future.delayed(widget.duration, () { + if (mounted) setState(() => copied = false); + }); + } + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: handleCopy, + child: widget.builder(context, copied), + ); + } + + // android 13 (sdk 33) added a built-in "text was copied to clipboard" ui element + Future shouldShowCopied() async { + if (!Platform.isAndroid) return true; + + try { + final deviceInfo = DeviceInfoPlugin(); + final androidInfo = await deviceInfo.androidInfo; + final sdk = androidInfo.version.sdkInt; + + return sdk < 33; + } catch (_) { + return true; + } + } +} diff --git a/lib/src/widgets/new_list_row/list_Item_style_wrapper.dart b/lib/src/widgets/new_list_row/list_Item_style_wrapper.dart index 88ebf59ce..d8a1186c5 100644 --- a/lib/src/widgets/new_list_row/list_Item_style_wrapper.dart +++ b/lib/src/widgets/new_list_row/list_Item_style_wrapper.dart @@ -6,6 +6,7 @@ class ListItemStyleWrapper extends StatelessWidget { required this.isFirstInSection, required this.isLastInSection, required this.builder, + this.backgroundColor, this.onTap, this.iconPath, this.height, @@ -16,6 +17,7 @@ class ListItemStyleWrapper extends StatelessWidget { final bool isLastInSection; final double? height; final VoidCallback? onTap; + final Color? backgroundColor; final Widget Function(BuildContext context, TextStyle textStyle, TextStyle labelStyle) builder; @override @@ -52,14 +54,14 @@ class ListItemStyleWrapper extends StatelessWidget { shape: RoundedSuperellipseBorder( borderRadius: radius, ), - color: theme.colorScheme.surfaceContainer, + color: backgroundColor ?? theme.colorScheme.surfaceContainer, ), child: Material( color: Colors.transparent, child: InkWell( onTap: onTap, child: Padding( - padding: EdgeInsets.symmetric(horizontal: 12, vertical: height == null ? 12 : 0), + padding: EdgeInsets.symmetric(horizontal: 12, vertical: height == null ? 11 : 0), child: builder(context, textStyle, labelStyle))))), if(iconPath != null && isLastInSection == false) Container( color: theme.colorScheme.surfaceContainer, diff --git a/lib/src/widgets/new_list_row/list_item_regular_row_widget.dart b/lib/src/widgets/new_list_row/list_item_regular_row_widget.dart index e60dcfbaf..47f5cc822 100644 --- a/lib/src/widgets/new_list_row/list_item_regular_row_widget.dart +++ b/lib/src/widgets/new_list_row/list_item_regular_row_widget.dart @@ -1,7 +1,9 @@ +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/new-ui/widgets/copy_wrapper.dart'; import 'package:cake_wallet/src/widgets/cake_image_widget.dart'; import 'package:cake_wallet/src/widgets/new_list_row/list_Item_style_wrapper.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; +import 'package:flutter/services.dart'; class ListItemRegularRowWidget extends StatelessWidget { const ListItemRegularRowWidget({ @@ -20,7 +22,8 @@ class ListItemRegularRowWidget extends StatelessWidget { this.foregroundColor, this.trailingIconSize, this.bottomWidget, - this.trailingWidget + this.trailingWidget, + this.copyableText }); final String keyValue; @@ -38,6 +41,7 @@ class ListItemRegularRowWidget extends StatelessWidget { final bool truncateTrailingText; final Color? foregroundColor; final double? trailingIconSize; + final String? copyableText; @override Widget build(BuildContext context) { @@ -47,79 +51,102 @@ class ListItemRegularRowWidget extends StatelessWidget { ? "${trailingText!.substring(0, 17)}..." : trailingText; - return ListItemStyleWrapper( - onTap: onTap, - iconPath: iconPath, - isFirstInSection: isFirstInSection, - isLastInSection: isLastInSection, - builder: (context, textStyle, labelStyle) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + return CopyWrapper( + data: copyableText != null ? ClipboardData(text: copyableText!) : null, + builder: (context, copied) => AnimatedSwitcher( + duration: Duration(milliseconds: 150), + child: ListItemStyleWrapper( + key: ValueKey(copied), + backgroundColor: copied ? Theme.of(context).colorScheme.surfaceContainerHigh : null, + onTap: onTap, + iconPath: iconPath, + isFirstInSection: isFirstInSection, + isLastInSection: isLastInSection, + builder: (context, textStyle, labelStyle) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ - Expanded( - child: Row( - children: [ - if (iconPath != null) - Padding( - padding: const EdgeInsets.only(right: 12.0), - child: CakeImageWidget(imageUrl: iconPath!, width: 24,height: 24,) - ), - Flexible( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(label, - style: foregroundColor == null - ? textStyle - : textStyle.copyWith(color: foregroundColor)), - if (subtitle != null) - Text( - subtitle!, - style: labelStyle.copyWith(fontSize: 12), - ), - ], - ), - ), - ], - ), - ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - if (trailingTextToShow != null) - Padding( - padding: const EdgeInsets.only(right: 8.0), - child: Text( - trailingTextToShow, - style: labelStyle, - ), + Expanded( + child: Row( + children: [ + if (iconPath != null) + Padding( + padding: const EdgeInsets.only(right: 12.0), + child: CakeImageWidget( + imageUrl: iconPath!, + width: 24, + height: 24, + )), + Flexible( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (copied) + Text( + S.of(context).copied, + style: textStyle.copyWith( + color: Theme.of(context).colorScheme.primary), + ) + else + Text(label, + style: foregroundColor == null + ? textStyle + : textStyle.copyWith(color: foregroundColor)), + if (subtitle != null) + Text( + subtitle!, + style: labelStyle.copyWith(fontSize: 12), + ), + ], + ), + ), + ], ), - if (trailingWidget != null) - trailingWidget! - else if (trailingIconPath != null) - CakeImageWidget(imageUrl: - trailingIconPath!, - height: trailingIconSize ?? 18, - width:trailingIconSize ?? 18, - colorFilter: ColorFilter.mode(foregroundColor ?? Theme.of(context).colorScheme.onSurfaceVariant,BlendMode.srcIn), - ) - else if (showArrow) - CakeImageWidget(imageUrl: - "assets/new-ui/arrow_forward.svg", - height: 14, - color: theme.colorScheme.onSurfaceVariant - ) + ), + Row( + children: [ + if (trailingTextToShow != null) + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Text( + trailingTextToShow, + style: labelStyle, + ), + ), + if (trailingWidget != null) + trailingWidget! + else if (trailingIconPath != null) + CakeImageWidget( + imageUrl: trailingIconPath!, + height: trailingIconSize ?? 18, + width: trailingIconSize ?? 18, + colorFilter: ColorFilter.mode( + foregroundColor ?? Theme.of(context).colorScheme.onSurfaceVariant, + BlendMode.srcIn), + ) + else if (showArrow) + Padding( + padding: const EdgeInsets.symmetric(vertical: 7.0), + child: CakeImageWidget(imageUrl: + "assets/new-ui/arrow_forward.svg", + height: 14, + color: theme.colorScheme.onSurfaceVariant + ), + ) + ], + ), ], ), + if (bottomWidget != null) bottomWidget! ], - ), - if (bottomWidget != null) bottomWidget! - ], - ); - }); + ); + }), + ), + ); } } diff --git a/lib/src/widgets/new_list_row/list_item_selector_widget.dart b/lib/src/widgets/new_list_row/list_item_selector_widget.dart index cb138906f..c0b9b9809 100644 --- a/lib/src/widgets/new_list_row/list_item_selector_widget.dart +++ b/lib/src/widgets/new_list_row/list_item_selector_widget.dart @@ -36,19 +36,22 @@ class ListItemSelectorWidget extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Flexible(child: Text(label, style: textStyle)), - Row( - spacing: 8, - children: [ - Text( - options[selectedIndex], - style: labelStyle, - ), - CakeImageWidget(imageUrl: - "assets/new-ui/chooser.svg", - colorFilter: - ColorFilter.mode(theme.colorScheme.onSurfaceVariant, BlendMode.srcIn), - ), - ], + Padding( + padding: const EdgeInsets.symmetric(vertical: 4.0), + child: Row( + spacing: 8, + children: [ + Text( + options[selectedIndex], + style: labelStyle, + ), + CakeImageWidget(imageUrl: + "assets/new-ui/chooser.svg", + colorFilter: + ColorFilter.mode(theme.colorScheme.onSurfaceVariant, BlendMode.srcIn), + ), + ], + ), ), ], ); diff --git a/lib/src/widgets/new_list_row/new_list_section.dart b/lib/src/widgets/new_list_row/new_list_section.dart index 21893d81e..196436124 100644 --- a/lib/src/widgets/new_list_row/new_list_section.dart +++ b/lib/src/widgets/new_list_row/new_list_section.dart @@ -103,6 +103,7 @@ class NewListSections extends StatelessWidget { showArrow: item.showArrow, truncateTrailingText: item.truncateTrailingText, foregroundColor: item.foregroundColor, + copyableText: item.copyableText, trailingIconSize: item.trailingIconSize, trailingWidget: item.trailingWidget, bottomWidget: item.bottomWidget, diff --git a/lib/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart index 269b93241..52c5954d8 100644 --- a/lib/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart +++ b/lib/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart @@ -51,6 +51,9 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store { _wallet.type == WalletType.litecoin || _wallet.type == WalletType.dogecoin; + String get derivationPath => _item?.derivationPath ?? ''; + String get index => _item?.id.toString() ?? ''; + Future save() async { try { state = AddressIsSaving(); diff --git a/lib/view_model/wallet_address_list/wallet_address_list_item.dart b/lib/view_model/wallet_address_list/wallet_address_list_item.dart index 2c5b0a3d9..97309173d 100644 --- a/lib/view_model/wallet_address_list/wallet_address_list_item.dart +++ b/lib/view_model/wallet_address_list/wallet_address_list_item.dart @@ -14,6 +14,7 @@ class WalletAddressListItem extends ListItem { this.isHidden = false, this.isManual = false, this.isLegacyDerivation = false, + this.derivationPath }) : super(); final int? id; @@ -26,6 +27,7 @@ class WalletAddressListItem extends ListItem { bool isHidden; bool isManual; bool isLegacyDerivation; + String? derivationPath; final bool? isOneTimeReceiveAddress; @override diff --git a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart index a517cc24b..4fc003077 100644 --- a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart +++ b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart @@ -258,6 +258,7 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo balance: _appStore.amountParsingProxy .getDisplayCryptoString(address.balance, walletTypeToCryptoCurrency(type)), isChange: address.isChange, + derivationPath: address.derivationPath, ); }); addressList.addAll(addressItems); @@ -275,6 +276,7 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo .getDisplayCryptoString(address.balance, walletTypeToCryptoCurrency(type)), isChange: address.isChange, isOneTimeReceiveAddress: true, + derivationPath: address.derivationPath, ); }); addressList.addAll(receivedAddressItems); @@ -291,7 +293,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo balance: _appStore.amountParsingProxy .getDisplayCryptoString(subaddress.balance, walletTypeToCryptoCurrency(type)), isChange: subaddress.isChange, - isLegacyDerivation: subaddress.isLegacyDerivation); + isLegacyDerivation: subaddress.isLegacyDerivation, + derivationPath: subaddress.derivationPath); }); // don't show all 1000+ mweb addresses: diff --git a/res/pictures/cake-setting.svg b/res/pictures/cake-setting.svg new file mode 100644 index 000000000..f3182f83d --- /dev/null +++ b/res/pictures/cake-setting.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/res/pictures/wallet-setting.svg b/res/pictures/wallet-setting.svg new file mode 100644 index 000000000..aa603df83 --- /dev/null +++ b/res/pictures/wallet-setting.svg @@ -0,0 +1,3 @@ + + + diff --git a/tool/configure.dart b/tool/configure.dart index 8e8da7183..c6ee96bc6 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -161,7 +161,7 @@ import "package:breez_sdk_spark_flutter/src/rust/errors.dart"; const bitcoinCwPart = "part 'cw_bitcoin.dart';"; const bitcoinContent = """ - class ElectrumSubAddress { +class ElectrumSubAddress { ElectrumSubAddress({ required this.id, required this.name, @@ -169,13 +169,16 @@ import "package:breez_sdk_spark_flutter/src/rust/errors.dart"; required this.txCount, required this.balance, required this.isChange, - this.isLegacyDerivation = false}); + this.derivationPath, + this.isLegacyDerivation = false + }); final int id; final String name; final String address; final int txCount; final int balance; final bool isChange; + final String? derivationPath; final bool isLegacyDerivation; }